blob: cf394e337167f92264a6c6ba205df1333836b158 [file] [log] [blame]
Aurimas Liutikasdc3f8852024-07-11 10:07:48 -07001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
30
31package com.google.protobuf;
32
33import static com.google.protobuf.Internal.checkNotNull;
34import static com.google.protobuf.WireFormat.FIXED32_SIZE;
35import static com.google.protobuf.WireFormat.FIXED64_SIZE;
36import static com.google.protobuf.WireFormat.MAX_VARINT32_SIZE;
37import static com.google.protobuf.WireFormat.MAX_VARINT64_SIZE;
38import static com.google.protobuf.WireFormat.MESSAGE_SET_ITEM;
39import static com.google.protobuf.WireFormat.MESSAGE_SET_MESSAGE;
40import static com.google.protobuf.WireFormat.MESSAGE_SET_TYPE_ID;
41import static com.google.protobuf.WireFormat.WIRETYPE_END_GROUP;
42import static com.google.protobuf.WireFormat.WIRETYPE_FIXED32;
43import static com.google.protobuf.WireFormat.WIRETYPE_FIXED64;
44import static com.google.protobuf.WireFormat.WIRETYPE_LENGTH_DELIMITED;
45import static com.google.protobuf.WireFormat.WIRETYPE_START_GROUP;
46import static com.google.protobuf.WireFormat.WIRETYPE_VARINT;
47
48import java.io.IOException;
49import java.nio.ByteBuffer;
50import java.nio.ByteOrder;
51import java.util.ArrayDeque;
52import java.util.List;
53import java.util.Map;
54import java.util.Queue;
55
56/**
57 * A protobuf writer that serializes messages in their binary form. Messages are serialized in
58 * reverse in order to avoid calculating the serialized size of each nested message. Since the
59 * message size is not known in advance, the writer employs a strategy of chunking and buffer
60 * chaining. Buffers are allocated as-needed by a provided {@link BufferAllocator}. Once writing is
61 * finished, the application can access the buffers in forward-writing order by calling {@link
62 * #complete()}.
63 *
64 * <p>Once {@link #complete()} has been called, the writer can not be reused for additional writes.
65 * The {@link #getTotalBytesWritten()} will continue to reflect the total of the write and will not
66 * be reset.
67 */
68@CheckReturnValue
69@ExperimentalApi
70abstract class BinaryWriter extends ByteOutput implements Writer {
71 public static final int DEFAULT_CHUNK_SIZE = 4096;
72
73 private final BufferAllocator alloc;
74 private final int chunkSize;
75
76 final ArrayDeque<AllocatedBuffer> buffers = new ArrayDeque<AllocatedBuffer>(4);
77 int totalDoneBytes;
78
79 /**
80 * Creates a new {@link BinaryWriter} that will allocate heap buffers of {@link
81 * #DEFAULT_CHUNK_SIZE} as necessary.
82 */
83 public static BinaryWriter newHeapInstance(BufferAllocator alloc) {
84 return newHeapInstance(alloc, DEFAULT_CHUNK_SIZE);
85 }
86
87 /**
88 * Creates a new {@link BinaryWriter} that will allocate heap buffers of {@code chunkSize} as
89 * necessary.
90 */
91 public static BinaryWriter newHeapInstance(BufferAllocator alloc, int chunkSize) {
92 return isUnsafeHeapSupported()
93 ? newUnsafeHeapInstance(alloc, chunkSize)
94 : newSafeHeapInstance(alloc, chunkSize);
95 }
96
97 /**
98 * Creates a new {@link BinaryWriter} that will allocate direct (i.e. non-heap) buffers of {@link
99 * #DEFAULT_CHUNK_SIZE} as necessary.
100 */
101 public static BinaryWriter newDirectInstance(BufferAllocator alloc) {
102 return newDirectInstance(alloc, DEFAULT_CHUNK_SIZE);
103 }
104
105 /**
106 * Creates a new {@link BinaryWriter} that will allocate direct (i.e. non-heap) buffers of {@code
107 * chunkSize} as necessary.
108 */
109 public static BinaryWriter newDirectInstance(BufferAllocator alloc, int chunkSize) {
110 return isUnsafeDirectSupported()
111 ? newUnsafeDirectInstance(alloc, chunkSize)
112 : newSafeDirectInstance(alloc, chunkSize);
113 }
114
115 static boolean isUnsafeHeapSupported() {
116 return UnsafeHeapWriter.isSupported();
117 }
118
119 static boolean isUnsafeDirectSupported() {
120 return UnsafeDirectWriter.isSupported();
121 }
122
123 static BinaryWriter newSafeHeapInstance(BufferAllocator alloc, int chunkSize) {
124 return new SafeHeapWriter(alloc, chunkSize);
125 }
126
127 static BinaryWriter newUnsafeHeapInstance(BufferAllocator alloc, int chunkSize) {
128 if (!isUnsafeHeapSupported()) {
129 throw new UnsupportedOperationException("Unsafe operations not supported");
130 }
131 return new UnsafeHeapWriter(alloc, chunkSize);
132 }
133
134 static BinaryWriter newSafeDirectInstance(BufferAllocator alloc, int chunkSize) {
135 return new SafeDirectWriter(alloc, chunkSize);
136 }
137
138 static BinaryWriter newUnsafeDirectInstance(BufferAllocator alloc, int chunkSize) {
139 if (!isUnsafeDirectSupported()) {
140 throw new UnsupportedOperationException("Unsafe operations not supported");
141 }
142 return new UnsafeDirectWriter(alloc, chunkSize);
143 }
144
145 /** Only allow subclassing for inner classes. */
146 private BinaryWriter(BufferAllocator alloc, int chunkSize) {
147 if (chunkSize <= 0) {
148 throw new IllegalArgumentException("chunkSize must be > 0");
149 }
150 this.alloc = checkNotNull(alloc, "alloc");
151 this.chunkSize = chunkSize;
152 }
153
154 @Override
155 public final FieldOrder fieldOrder() {
156 return FieldOrder.DESCENDING;
157 }
158
159 /**
160 * Completes the write operation and returns a queue of {@link AllocatedBuffer} objects in
161 * forward-writing order. This method should only be called once.
162 *
163 * <p>After calling this method, the writer can not be reused. Create a new writer for future
164 * writes.
165 */
166 @CanIgnoreReturnValue
167 public final Queue<AllocatedBuffer> complete() {
168 finishCurrentBuffer();
169 return buffers;
170 }
171
172 @Override
173 public final void writeSFixed32(int fieldNumber, int value) throws IOException {
174 writeFixed32(fieldNumber, value);
175 }
176
177 @Override
178 public final void writeInt64(int fieldNumber, long value) throws IOException {
179 writeUInt64(fieldNumber, value);
180 }
181
182 @Override
183 public final void writeSFixed64(int fieldNumber, long value) throws IOException {
184 writeFixed64(fieldNumber, value);
185 }
186
187 @Override
188 public final void writeFloat(int fieldNumber, float value) throws IOException {
189 writeFixed32(fieldNumber, Float.floatToRawIntBits(value));
190 }
191
192 @Override
193 public final void writeDouble(int fieldNumber, double value) throws IOException {
194 writeFixed64(fieldNumber, Double.doubleToRawLongBits(value));
195 }
196
197 @Override
198 public final void writeEnum(int fieldNumber, int value) throws IOException {
199 writeInt32(fieldNumber, value);
200 }
201
202 @Override
203 public final void writeInt32List(int fieldNumber, List<Integer> list, boolean packed)
204 throws IOException {
205 if (list instanceof IntArrayList) {
206 writeInt32List_Internal(fieldNumber, (IntArrayList) list, packed);
207 } else {
208 writeInt32List_Internal(fieldNumber, list, packed);
209 }
210 }
211
212 private final void writeInt32List_Internal(int fieldNumber, List<Integer> list, boolean packed)
213 throws IOException {
214 if (packed) {
215 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
216 int prevBytes = getTotalBytesWritten();
217 for (int i = list.size() - 1; i >= 0; --i) {
218 writeInt32(list.get(i));
219 }
220 int length = getTotalBytesWritten() - prevBytes;
221 writeVarint32(length);
222 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
223 } else {
224 for (int i = list.size() - 1; i >= 0; --i) {
225 writeInt32(fieldNumber, list.get(i));
226 }
227 }
228 }
229
230 private final void writeInt32List_Internal(int fieldNumber, IntArrayList list, boolean packed)
231 throws IOException {
232 if (packed) {
233 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
234 int prevBytes = getTotalBytesWritten();
235 for (int i = list.size() - 1; i >= 0; --i) {
236 writeInt32(list.getInt(i));
237 }
238 int length = getTotalBytesWritten() - prevBytes;
239 writeVarint32(length);
240 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
241 } else {
242 for (int i = list.size() - 1; i >= 0; --i) {
243 writeInt32(fieldNumber, list.getInt(i));
244 }
245 }
246 }
247
248 @Override
249 public final void writeFixed32List(int fieldNumber, List<Integer> list, boolean packed)
250 throws IOException {
251 if (list instanceof IntArrayList) {
252 writeFixed32List_Internal(fieldNumber, (IntArrayList) list, packed);
253 } else {
254 writeFixed32List_Internal(fieldNumber, list, packed);
255 }
256 }
257
258 private final void writeFixed32List_Internal(int fieldNumber, List<Integer> list, boolean packed)
259 throws IOException {
260 if (packed) {
261 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED32_SIZE));
262 int prevBytes = getTotalBytesWritten();
263 for (int i = list.size() - 1; i >= 0; --i) {
264 writeFixed32(list.get(i));
265 }
266 int length = getTotalBytesWritten() - prevBytes;
267 writeVarint32(length);
268 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
269 } else {
270 for (int i = list.size() - 1; i >= 0; --i) {
271 writeFixed32(fieldNumber, list.get(i));
272 }
273 }
274 }
275
276 private final void writeFixed32List_Internal(int fieldNumber, IntArrayList list, boolean packed)
277 throws IOException {
278 if (packed) {
279 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED32_SIZE));
280 int prevBytes = getTotalBytesWritten();
281 for (int i = list.size() - 1; i >= 0; --i) {
282 writeFixed32(list.getInt(i));
283 }
284 int length = getTotalBytesWritten() - prevBytes;
285 writeVarint32(length);
286 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
287 } else {
288 for (int i = list.size() - 1; i >= 0; --i) {
289 writeFixed32(fieldNumber, list.getInt(i));
290 }
291 }
292 }
293
294 @Override
295 public final void writeInt64List(int fieldNumber, List<Long> list, boolean packed)
296 throws IOException {
297 writeUInt64List(fieldNumber, list, packed);
298 }
299
300 @Override
301 public final void writeUInt64List(int fieldNumber, List<Long> list, boolean packed)
302 throws IOException {
303 if (list instanceof LongArrayList) {
304 writeUInt64List_Internal(fieldNumber, (LongArrayList) list, packed);
305 } else {
306 writeUInt64List_Internal(fieldNumber, list, packed);
307 }
308 }
309
310 private final void writeUInt64List_Internal(int fieldNumber, List<Long> list, boolean packed)
311 throws IOException {
312 if (packed) {
313 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
314 int prevBytes = getTotalBytesWritten();
315 for (int i = list.size() - 1; i >= 0; --i) {
316 writeVarint64(list.get(i));
317 }
318 int length = getTotalBytesWritten() - prevBytes;
319 writeVarint32(length);
320 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
321 } else {
322 for (int i = list.size() - 1; i >= 0; --i) {
323 writeUInt64(fieldNumber, list.get(i));
324 }
325 }
326 }
327
328 private final void writeUInt64List_Internal(int fieldNumber, LongArrayList list, boolean packed)
329 throws IOException {
330 if (packed) {
331 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
332 int prevBytes = getTotalBytesWritten();
333 for (int i = list.size() - 1; i >= 0; --i) {
334 writeVarint64(list.getLong(i));
335 }
336 int length = getTotalBytesWritten() - prevBytes;
337 writeVarint32(length);
338 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
339 } else {
340 for (int i = list.size() - 1; i >= 0; --i) {
341 writeUInt64(fieldNumber, list.getLong(i));
342 }
343 }
344 }
345
346 @Override
347 public final void writeFixed64List(int fieldNumber, List<Long> list, boolean packed)
348 throws IOException {
349 if (list instanceof LongArrayList) {
350 writeFixed64List_Internal(fieldNumber, (LongArrayList) list, packed);
351 } else {
352 writeFixed64List_Internal(fieldNumber, list, packed);
353 }
354 }
355
356 private final void writeFixed64List_Internal(int fieldNumber, List<Long> list, boolean packed)
357 throws IOException {
358 if (packed) {
359 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED64_SIZE));
360 int prevBytes = getTotalBytesWritten();
361 for (int i = list.size() - 1; i >= 0; --i) {
362 writeFixed64(list.get(i));
363 }
364 int length = getTotalBytesWritten() - prevBytes;
365 writeVarint32(length);
366 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
367 } else {
368 for (int i = list.size() - 1; i >= 0; --i) {
369 writeFixed64(fieldNumber, list.get(i));
370 }
371 }
372 }
373
374 private final void writeFixed64List_Internal(int fieldNumber, LongArrayList list, boolean packed)
375 throws IOException {
376 if (packed) {
377 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED64_SIZE));
378 int prevBytes = getTotalBytesWritten();
379 for (int i = list.size() - 1; i >= 0; --i) {
380 writeFixed64(list.getLong(i));
381 }
382 int length = getTotalBytesWritten() - prevBytes;
383 writeVarint32(length);
384 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
385 } else {
386 for (int i = list.size() - 1; i >= 0; --i) {
387 writeFixed64(fieldNumber, list.getLong(i));
388 }
389 }
390 }
391
392 @Override
393 public final void writeFloatList(int fieldNumber, List<Float> list, boolean packed)
394 throws IOException {
395 if (list instanceof FloatArrayList) {
396 writeFloatList_Internal(fieldNumber, (FloatArrayList) list, packed);
397 } else {
398 writeFloatList_Internal(fieldNumber, list, packed);
399 }
400 }
401
402 private final void writeFloatList_Internal(int fieldNumber, List<Float> list, boolean packed)
403 throws IOException {
404 if (packed) {
405 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED32_SIZE));
406 int prevBytes = getTotalBytesWritten();
407 for (int i = list.size() - 1; i >= 0; --i) {
408 writeFixed32(Float.floatToRawIntBits(list.get(i)));
409 }
410 int length = getTotalBytesWritten() - prevBytes;
411 writeVarint32(length);
412 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
413 } else {
414 for (int i = list.size() - 1; i >= 0; --i) {
415 writeFloat(fieldNumber, list.get(i));
416 }
417 }
418 }
419
420 private final void writeFloatList_Internal(int fieldNumber, FloatArrayList list, boolean packed)
421 throws IOException {
422 if (packed) {
423 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED32_SIZE));
424 int prevBytes = getTotalBytesWritten();
425 for (int i = list.size() - 1; i >= 0; --i) {
426 writeFixed32(Float.floatToRawIntBits(list.getFloat(i)));
427 }
428 int length = getTotalBytesWritten() - prevBytes;
429 writeVarint32(length);
430 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
431 } else {
432 for (int i = list.size() - 1; i >= 0; --i) {
433 writeFloat(fieldNumber, list.getFloat(i));
434 }
435 }
436 }
437
438 @Override
439 public final void writeDoubleList(int fieldNumber, List<Double> list, boolean packed)
440 throws IOException {
441 if (list instanceof DoubleArrayList) {
442 writeDoubleList_Internal(fieldNumber, (DoubleArrayList) list, packed);
443 } else {
444 writeDoubleList_Internal(fieldNumber, list, packed);
445 }
446 }
447
448 private final void writeDoubleList_Internal(int fieldNumber, List<Double> list, boolean packed)
449 throws IOException {
450 if (packed) {
451 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED64_SIZE));
452 int prevBytes = getTotalBytesWritten();
453 for (int i = list.size() - 1; i >= 0; --i) {
454 writeFixed64(Double.doubleToRawLongBits(list.get(i)));
455 }
456 int length = getTotalBytesWritten() - prevBytes;
457 writeVarint32(length);
458 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
459 } else {
460 for (int i = list.size() - 1; i >= 0; --i) {
461 writeDouble(fieldNumber, list.get(i));
462 }
463 }
464 }
465
466 private final void writeDoubleList_Internal(int fieldNumber, DoubleArrayList list, boolean packed)
467 throws IOException {
468 if (packed) {
469 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED64_SIZE));
470 int prevBytes = getTotalBytesWritten();
471 for (int i = list.size() - 1; i >= 0; --i) {
472 writeFixed64(Double.doubleToRawLongBits(list.getDouble(i)));
473 }
474 int length = getTotalBytesWritten() - prevBytes;
475 writeVarint32(length);
476 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
477 } else {
478 for (int i = list.size() - 1; i >= 0; --i) {
479 writeDouble(fieldNumber, list.getDouble(i));
480 }
481 }
482 }
483
484 @Override
485 public final void writeEnumList(int fieldNumber, List<Integer> list, boolean packed)
486 throws IOException {
487 writeInt32List(fieldNumber, list, packed);
488 }
489
490 @Override
491 public final void writeBoolList(int fieldNumber, List<Boolean> list, boolean packed)
492 throws IOException {
493 if (list instanceof BooleanArrayList) {
494 writeBoolList_Internal(fieldNumber, (BooleanArrayList) list, packed);
495 } else {
496 writeBoolList_Internal(fieldNumber, list, packed);
497 }
498 }
499
500 private final void writeBoolList_Internal(int fieldNumber, List<Boolean> list, boolean packed)
501 throws IOException {
502 if (packed) {
503 requireSpace((MAX_VARINT32_SIZE * 2) + list.size());
504 int prevBytes = getTotalBytesWritten();
505 for (int i = list.size() - 1; i >= 0; --i) {
506 writeBool(list.get(i));
507 }
508 int length = getTotalBytesWritten() - prevBytes;
509 writeVarint32(length);
510 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
511 } else {
512 for (int i = list.size() - 1; i >= 0; --i) {
513 writeBool(fieldNumber, list.get(i));
514 }
515 }
516 }
517
518 private final void writeBoolList_Internal(int fieldNumber, BooleanArrayList list, boolean packed)
519 throws IOException {
520 if (packed) {
521 requireSpace((MAX_VARINT32_SIZE * 2) + list.size());
522 int prevBytes = getTotalBytesWritten();
523 for (int i = list.size() - 1; i >= 0; --i) {
524 writeBool(list.getBoolean(i));
525 }
526 int length = getTotalBytesWritten() - prevBytes;
527 writeVarint32(length);
528 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
529 } else {
530 for (int i = list.size() - 1; i >= 0; --i) {
531 writeBool(fieldNumber, list.getBoolean(i));
532 }
533 }
534 }
535
536 @Override
537 public final void writeStringList(int fieldNumber, List<String> list) throws IOException {
538 if (list instanceof LazyStringList) {
539 final LazyStringList lazyList = (LazyStringList) list;
540 for (int i = list.size() - 1; i >= 0; i--) {
541 writeLazyString(fieldNumber, lazyList.getRaw(i));
542 }
543 } else {
544 for (int i = list.size() - 1; i >= 0; i--) {
545 writeString(fieldNumber, list.get(i));
546 }
547 }
548 }
549
550 private void writeLazyString(int fieldNumber, Object value) throws IOException {
551 if (value instanceof String) {
552 writeString(fieldNumber, (String) value);
553 } else {
554 writeBytes(fieldNumber, (ByteString) value);
555 }
556 }
557
558 @Override
559 public final void writeBytesList(int fieldNumber, List<ByteString> list) throws IOException {
560 for (int i = list.size() - 1; i >= 0; i--) {
561 writeBytes(fieldNumber, list.get(i));
562 }
563 }
564
565 @Override
566 public final void writeUInt32List(int fieldNumber, List<Integer> list, boolean packed)
567 throws IOException {
568 if (list instanceof IntArrayList) {
569 writeUInt32List_Internal(fieldNumber, (IntArrayList) list, packed);
570 } else {
571 writeUInt32List_Internal(fieldNumber, list, packed);
572 }
573 }
574
575 private final void writeUInt32List_Internal(int fieldNumber, List<Integer> list, boolean packed)
576 throws IOException {
577 if (packed) {
578 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT32_SIZE));
579 int prevBytes = getTotalBytesWritten();
580 for (int i = list.size() - 1; i >= 0; --i) {
581 writeVarint32(list.get(i));
582 }
583 int length = getTotalBytesWritten() - prevBytes;
584 writeVarint32(length);
585 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
586 } else {
587 for (int i = list.size() - 1; i >= 0; --i) {
588 writeUInt32(fieldNumber, list.get(i));
589 }
590 }
591 }
592
593 private final void writeUInt32List_Internal(int fieldNumber, IntArrayList list, boolean packed)
594 throws IOException {
595 if (packed) {
596 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT32_SIZE));
597 int prevBytes = getTotalBytesWritten();
598 for (int i = list.size() - 1; i >= 0; --i) {
599 writeVarint32(list.getInt(i));
600 }
601 int length = getTotalBytesWritten() - prevBytes;
602 writeVarint32(length);
603 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
604 } else {
605 for (int i = list.size() - 1; i >= 0; --i) {
606 writeUInt32(fieldNumber, list.getInt(i));
607 }
608 }
609 }
610
611 @Override
612 public final void writeSFixed32List(int fieldNumber, List<Integer> list, boolean packed)
613 throws IOException {
614 writeFixed32List(fieldNumber, list, packed);
615 }
616
617 @Override
618 public final void writeSFixed64List(int fieldNumber, List<Long> list, boolean packed)
619 throws IOException {
620 writeFixed64List(fieldNumber, list, packed);
621 }
622
623 @Override
624 public final void writeSInt32List(int fieldNumber, List<Integer> list, boolean packed)
625 throws IOException {
626 if (list instanceof IntArrayList) {
627 writeSInt32List_Internal(fieldNumber, (IntArrayList) list, packed);
628 } else {
629 writeSInt32List_Internal(fieldNumber, list, packed);
630 }
631 }
632
633 private final void writeSInt32List_Internal(int fieldNumber, List<Integer> list, boolean packed)
634 throws IOException {
635 if (packed) {
636 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT32_SIZE));
637 int prevBytes = getTotalBytesWritten();
638 for (int i = list.size() - 1; i >= 0; --i) {
639 writeSInt32(list.get(i));
640 }
641 int length = getTotalBytesWritten() - prevBytes;
642 writeVarint32(length);
643 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
644 } else {
645 for (int i = list.size() - 1; i >= 0; --i) {
646 writeSInt32(fieldNumber, list.get(i));
647 }
648 }
649 }
650
651 private final void writeSInt32List_Internal(int fieldNumber, IntArrayList list, boolean packed)
652 throws IOException {
653 if (packed) {
654 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT32_SIZE));
655 int prevBytes = getTotalBytesWritten();
656 for (int i = list.size() - 1; i >= 0; --i) {
657 writeSInt32(list.getInt(i));
658 }
659 int length = getTotalBytesWritten() - prevBytes;
660 writeVarint32(length);
661 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
662 } else {
663 for (int i = list.size() - 1; i >= 0; --i) {
664 writeSInt32(fieldNumber, list.getInt(i));
665 }
666 }
667 }
668
669 @Override
670 public final void writeSInt64List(int fieldNumber, List<Long> list, boolean packed)
671 throws IOException {
672 if (list instanceof LongArrayList) {
673 writeSInt64List_Internal(fieldNumber, (LongArrayList) list, packed);
674 } else {
675 writeSInt64List_Internal(fieldNumber, list, packed);
676 }
677 }
678
679 private static final int MAP_KEY_NUMBER = 1;
680 private static final int MAP_VALUE_NUMBER = 2;
681
682 @Override
683 public <K, V> void writeMap(int fieldNumber, MapEntryLite.Metadata<K, V> metadata, Map<K, V> map)
684 throws IOException {
685 // TODO(liujisi): Reverse write those entries.
686 for (Map.Entry<K, V> entry : map.entrySet()) {
687 int prevBytes = getTotalBytesWritten();
688 writeMapEntryField(this, MAP_VALUE_NUMBER, metadata.valueType, entry.getValue());
689 writeMapEntryField(this, MAP_KEY_NUMBER, metadata.keyType, entry.getKey());
690 int length = getTotalBytesWritten() - prevBytes;
691 writeVarint32(length);
692 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
693 }
694 }
695
696 static final void writeMapEntryField(
697 Writer writer, int fieldNumber, WireFormat.FieldType fieldType, Object object)
698 throws IOException {
699 switch (fieldType) {
700 case BOOL:
701 writer.writeBool(fieldNumber, (Boolean) object);
702 break;
703 case FIXED32:
704 writer.writeFixed32(fieldNumber, (Integer) object);
705 break;
706 case FIXED64:
707 writer.writeFixed64(fieldNumber, (Long) object);
708 break;
709 case INT32:
710 writer.writeInt32(fieldNumber, (Integer) object);
711 break;
712 case INT64:
713 writer.writeInt64(fieldNumber, (Long) object);
714 break;
715 case SFIXED32:
716 writer.writeSFixed32(fieldNumber, (Integer) object);
717 break;
718 case SFIXED64:
719 writer.writeSFixed64(fieldNumber, (Long) object);
720 break;
721 case SINT32:
722 writer.writeSInt32(fieldNumber, (Integer) object);
723 break;
724 case SINT64:
725 writer.writeSInt64(fieldNumber, (Long) object);
726 break;
727 case STRING:
728 writer.writeString(fieldNumber, (String) object);
729 break;
730 case UINT32:
731 writer.writeUInt32(fieldNumber, (Integer) object);
732 break;
733 case UINT64:
734 writer.writeUInt64(fieldNumber, (Long) object);
735 break;
736 case FLOAT:
737 writer.writeFloat(fieldNumber, (Float) object);
738 break;
739 case DOUBLE:
740 writer.writeDouble(fieldNumber, (Double) object);
741 break;
742 case MESSAGE:
743 writer.writeMessage(fieldNumber, object);
744 break;
745 case BYTES:
746 writer.writeBytes(fieldNumber, (ByteString) object);
747 break;
748 case ENUM:
749 if (object instanceof Internal.EnumLite) {
750 writer.writeEnum(fieldNumber, ((Internal.EnumLite) object).getNumber());
751 } else if (object instanceof Integer) {
752 writer.writeEnum(fieldNumber, (Integer) object);
753 } else {
754 throw new IllegalArgumentException("Unexpected type for enum in map.");
755 }
756 break;
757 default:
758 throw new IllegalArgumentException("Unsupported map value type for: " + fieldType);
759 }
760 }
761
762 private final void writeSInt64List_Internal(int fieldNumber, List<Long> list, boolean packed)
763 throws IOException {
764 if (packed) {
765 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
766 int prevBytes = getTotalBytesWritten();
767 for (int i = list.size() - 1; i >= 0; --i) {
768 writeSInt64(list.get(i));
769 }
770 int length = getTotalBytesWritten() - prevBytes;
771 writeVarint32(length);
772 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
773 } else {
774 for (int i = list.size() - 1; i >= 0; --i) {
775 writeSInt64(fieldNumber, list.get(i));
776 }
777 }
778 }
779
780 private final void writeSInt64List_Internal(int fieldNumber, LongArrayList list, boolean packed)
781 throws IOException {
782 if (packed) {
783 requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
784 int prevBytes = getTotalBytesWritten();
785 for (int i = list.size() - 1; i >= 0; --i) {
786 writeSInt64(list.getLong(i));
787 }
788 int length = getTotalBytesWritten() - prevBytes;
789 writeVarint32(length);
790 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
791 } else {
792 for (int i = list.size() - 1; i >= 0; --i) {
793 writeSInt64(fieldNumber, list.getLong(i));
794 }
795 }
796 }
797
798 @Override
799 public final void writeMessageList(int fieldNumber, List<?> list) throws IOException {
800 for (int i = list.size() - 1; i >= 0; i--) {
801 writeMessage(fieldNumber, list.get(i));
802 }
803 }
804
805 @Override
806 public final void writeMessageList(int fieldNumber, List<?> list, Schema schema)
807 throws IOException {
808 for (int i = list.size() - 1; i >= 0; i--) {
809 writeMessage(fieldNumber, list.get(i), schema);
810 }
811 }
812
813 @Deprecated
814 @Override
815 public final void writeGroupList(int fieldNumber, List<?> list) throws IOException {
816 for (int i = list.size() - 1; i >= 0; i--) {
817 writeGroup(fieldNumber, list.get(i));
818 }
819 }
820
821 @Deprecated
822 @Override
823 public final void writeGroupList(int fieldNumber, List<?> list, Schema schema)
824 throws IOException {
825 for (int i = list.size() - 1; i >= 0; i--) {
826 writeGroup(fieldNumber, list.get(i), schema);
827 }
828 }
829
830 @Override
831 public final void writeMessageSetItem(int fieldNumber, Object value) throws IOException {
832 writeTag(MESSAGE_SET_ITEM, WIRETYPE_END_GROUP);
833 if (value instanceof ByteString) {
834 writeBytes(MESSAGE_SET_MESSAGE, (ByteString) value);
835 } else {
836 writeMessage(MESSAGE_SET_MESSAGE, value);
837 }
838 writeUInt32(MESSAGE_SET_TYPE_ID, fieldNumber);
839 writeTag(MESSAGE_SET_ITEM, WIRETYPE_START_GROUP);
840 }
841
842 final AllocatedBuffer newHeapBuffer() {
843 return alloc.allocateHeapBuffer(chunkSize);
844 }
845
846 final AllocatedBuffer newHeapBuffer(int capacity) {
847 return alloc.allocateHeapBuffer(Math.max(capacity, chunkSize));
848 }
849
850 final AllocatedBuffer newDirectBuffer() {
851 return alloc.allocateDirectBuffer(chunkSize);
852 }
853
854 final AllocatedBuffer newDirectBuffer(int capacity) {
855 return alloc.allocateDirectBuffer(Math.max(capacity, chunkSize));
856 }
857
858 /**
859 * Gets the total number of bytes that have been written. This will not be reset by a call to
860 * {@link #complete()}.
861 */
862 public abstract int getTotalBytesWritten();
863
864 abstract void requireSpace(int size);
865
866 abstract void finishCurrentBuffer();
867
868 abstract void writeTag(int fieldNumber, int wireType);
869
870 abstract void writeVarint32(int value);
871
872 abstract void writeInt32(int value);
873
874 abstract void writeSInt32(int value);
875
876 abstract void writeFixed32(int value);
877
878 abstract void writeVarint64(long value);
879
880 abstract void writeSInt64(long value);
881
882 abstract void writeFixed64(long value);
883
884 abstract void writeBool(boolean value);
885
886 abstract void writeString(String in);
887
888 /**
889 * Not using the version in CodedOutputStream due to the fact that benchmarks have shown a
890 * performance improvement when returning a byte (rather than an int).
891 */
892 private static byte computeUInt64SizeNoTag(long value) {
893 // handle two popular special cases up front ...
894 if ((value & (~0L << 7)) == 0L) {
895 // Byte 1
896 return 1;
897 }
898 if (value < 0L) {
899 // Byte 10
900 return 10;
901 }
902 // ... leaving us with 8 remaining, which we can divide and conquer
903 byte n = 2;
904 if ((value & (~0L << 35)) != 0L) {
905 // Byte 6-9
906 n += 4; // + (value >>> 63);
907 value >>>= 28;
908 }
909 if ((value & (~0L << 21)) != 0L) {
910 // Byte 4-5 or 8-9
911 n += 2;
912 value >>>= 14;
913 }
914 if ((value & (~0L << 14)) != 0L) {
915 // Byte 3 or 7
916 n += 1;
917 }
918 return n;
919 }
920
921 /** Writer that uses safe operations on target array. */
922 private static final class SafeHeapWriter extends BinaryWriter {
923 private AllocatedBuffer allocatedBuffer;
924 private byte[] buffer;
925 private int offset;
926 private int limit;
927 private int offsetMinusOne;
928 private int limitMinusOne;
929 private int pos;
930
931 SafeHeapWriter(BufferAllocator alloc, int chunkSize) {
932 super(alloc, chunkSize);
933 nextBuffer();
934 }
935
936 @Override
937 void finishCurrentBuffer() {
938 if (allocatedBuffer != null) {
939 totalDoneBytes += bytesWrittenToCurrentBuffer();
940 allocatedBuffer.position((pos - allocatedBuffer.arrayOffset()) + 1);
941 allocatedBuffer = null;
942 pos = 0;
943 limitMinusOne = 0;
944 }
945 }
946
947 private void nextBuffer() {
948 nextBuffer(newHeapBuffer());
949 }
950
951 private void nextBuffer(int capacity) {
952 nextBuffer(newHeapBuffer(capacity));
953 }
954
955 private void nextBuffer(AllocatedBuffer allocatedBuffer) {
956 if (!allocatedBuffer.hasArray()) {
957 throw new RuntimeException("Allocator returned non-heap buffer");
958 }
959
960 finishCurrentBuffer();
961
962 buffers.addFirst(allocatedBuffer);
963
964 this.allocatedBuffer = allocatedBuffer;
965 this.buffer = allocatedBuffer.array();
966 int arrayOffset = allocatedBuffer.arrayOffset();
967 this.limit = arrayOffset + allocatedBuffer.limit();
968 this.offset = arrayOffset + allocatedBuffer.position();
969 this.offsetMinusOne = offset - 1;
970 this.limitMinusOne = limit - 1;
971 this.pos = limitMinusOne;
972 }
973
974 @Override
975 public int getTotalBytesWritten() {
976 return totalDoneBytes + bytesWrittenToCurrentBuffer();
977 }
978
979 int bytesWrittenToCurrentBuffer() {
980 return limitMinusOne - pos;
981 }
982
983 int spaceLeft() {
984 return pos - offsetMinusOne;
985 }
986
987 @Override
988 public void writeUInt32(int fieldNumber, int value) throws IOException {
989 requireSpace(MAX_VARINT32_SIZE * 2);
990 writeVarint32(value);
991 writeTag(fieldNumber, WIRETYPE_VARINT);
992 }
993
994 @Override
995 public void writeInt32(int fieldNumber, int value) throws IOException {
996 requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
997 writeInt32(value);
998 writeTag(fieldNumber, WIRETYPE_VARINT);
999 }
1000
1001 @Override
1002 public void writeSInt32(int fieldNumber, int value) throws IOException {
1003 requireSpace(MAX_VARINT32_SIZE * 2);
1004 writeSInt32(value);
1005 writeTag(fieldNumber, WIRETYPE_VARINT);
1006 }
1007
1008 @Override
1009 public void writeFixed32(int fieldNumber, int value) throws IOException {
1010 requireSpace(MAX_VARINT32_SIZE + FIXED32_SIZE);
1011 writeFixed32(value);
1012 writeTag(fieldNumber, WIRETYPE_FIXED32);
1013 }
1014
1015 @Override
1016 public void writeUInt64(int fieldNumber, long value) throws IOException {
1017 requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
1018 writeVarint64(value);
1019 writeTag(fieldNumber, WIRETYPE_VARINT);
1020 }
1021
1022 @Override
1023 public void writeSInt64(int fieldNumber, long value) throws IOException {
1024 requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
1025 writeSInt64(value);
1026 writeTag(fieldNumber, WIRETYPE_VARINT);
1027 }
1028
1029 @Override
1030 public void writeFixed64(int fieldNumber, long value) throws IOException {
1031 requireSpace(MAX_VARINT32_SIZE + FIXED64_SIZE);
1032 writeFixed64(value);
1033 writeTag(fieldNumber, WIRETYPE_FIXED64);
1034 }
1035
1036 @Override
1037 public void writeBool(int fieldNumber, boolean value) throws IOException {
1038 requireSpace(MAX_VARINT32_SIZE + 1);
1039 write((byte) (value ? 1 : 0));
1040 writeTag(fieldNumber, WIRETYPE_VARINT);
1041 }
1042
1043 @Override
1044 public void writeString(int fieldNumber, String value) throws IOException {
1045 int prevBytes = getTotalBytesWritten();
1046 writeString(value);
1047 int length = getTotalBytesWritten() - prevBytes;
1048 requireSpace(2 * MAX_VARINT32_SIZE);
1049 writeVarint32(length);
1050 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
1051 }
1052
1053 @Override
1054 public void writeBytes(int fieldNumber, ByteString value) throws IOException {
1055 try {
1056 value.writeToReverse(this);
1057 } catch (IOException e) {
1058 // Should never happen since the writer does not throw.
1059 throw new RuntimeException(e);
1060 }
1061
1062 requireSpace(MAX_VARINT32_SIZE * 2);
1063 writeVarint32(value.size());
1064 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
1065 }
1066
1067 @Override
1068 public void writeMessage(int fieldNumber, Object value) throws IOException {
1069 int prevBytes = getTotalBytesWritten();
1070 Protobuf.getInstance().writeTo(value, this);
1071 int length = getTotalBytesWritten() - prevBytes;
1072 requireSpace(MAX_VARINT32_SIZE * 2);
1073 writeVarint32(length);
1074 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
1075 }
1076
1077 @Override
1078 public void writeMessage(int fieldNumber, Object value, Schema schema) throws IOException {
1079 int prevBytes = getTotalBytesWritten();
1080 schema.writeTo(value, this);
1081 int length = getTotalBytesWritten() - prevBytes;
1082 requireSpace(MAX_VARINT32_SIZE * 2);
1083 writeVarint32(length);
1084 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
1085 }
1086
1087 @Deprecated
1088 @Override
1089 public void writeGroup(int fieldNumber, Object value) throws IOException {
1090 writeTag(fieldNumber, WIRETYPE_END_GROUP);
1091 Protobuf.getInstance().writeTo(value, this);
1092 writeTag(fieldNumber, WIRETYPE_START_GROUP);
1093 }
1094
1095 @Override
1096 public void writeGroup(int fieldNumber, Object value, Schema schema) throws IOException {
1097 writeTag(fieldNumber, WIRETYPE_END_GROUP);
1098 schema.writeTo(value, this);
1099 writeTag(fieldNumber, WIRETYPE_START_GROUP);
1100 }
1101
1102 @Override
1103 public void writeStartGroup(int fieldNumber) {
1104 writeTag(fieldNumber, WIRETYPE_START_GROUP);
1105 }
1106
1107 @Override
1108 public void writeEndGroup(int fieldNumber) {
1109 writeTag(fieldNumber, WIRETYPE_END_GROUP);
1110 }
1111
1112 @Override
1113 void writeInt32(int value) {
1114 if (value >= 0) {
1115 writeVarint32(value);
1116 } else {
1117 writeVarint64(value);
1118 }
1119 }
1120
1121 @Override
1122 void writeSInt32(int value) {
1123 writeVarint32(CodedOutputStream.encodeZigZag32(value));
1124 }
1125
1126 @Override
1127 void writeSInt64(long value) {
1128 writeVarint64(CodedOutputStream.encodeZigZag64(value));
1129 }
1130
1131 @Override
1132 void writeBool(boolean value) {
1133 write((byte) (value ? 1 : 0));
1134 }
1135
1136 @Override
1137 void writeTag(int fieldNumber, int wireType) {
1138 writeVarint32(WireFormat.makeTag(fieldNumber, wireType));
1139 }
1140
1141 @Override
1142 void writeVarint32(int value) {
1143 if ((value & (~0 << 7)) == 0) {
1144 writeVarint32OneByte(value);
1145 } else if ((value & (~0 << 14)) == 0) {
1146 writeVarint32TwoBytes(value);
1147 } else if ((value & (~0 << 21)) == 0) {
1148 writeVarint32ThreeBytes(value);
1149 } else if ((value & (~0 << 28)) == 0) {
1150 writeVarint32FourBytes(value);
1151 } else {
1152 writeVarint32FiveBytes(value);
1153 }
1154 }
1155
1156 private void writeVarint32OneByte(int value) {
1157 buffer[pos--] = (byte) value;
1158 }
1159
1160 private void writeVarint32TwoBytes(int value) {
1161 buffer[pos--] = (byte) (value >>> 7);
1162 buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
1163 }
1164
1165 private void writeVarint32ThreeBytes(int value) {
1166 buffer[pos--] = (byte) (value >>> 14);
1167 buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
1168 buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
1169 }
1170
1171 private void writeVarint32FourBytes(int value) {
1172 buffer[pos--] = (byte) (value >>> 21);
1173 buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
1174 buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
1175 buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
1176 }
1177
1178 private void writeVarint32FiveBytes(int value) {
1179 buffer[pos--] = (byte) (value >>> 28);
1180 buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80);
1181 buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
1182 buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
1183 buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
1184 }
1185
1186 @Override
1187 void writeVarint64(long value) {
1188 switch (computeUInt64SizeNoTag(value)) {
1189 case 1:
1190 writeVarint64OneByte(value);
1191 break;
1192 case 2:
1193 writeVarint64TwoBytes(value);
1194 break;
1195 case 3:
1196 writeVarint64ThreeBytes(value);
1197 break;
1198 case 4:
1199 writeVarint64FourBytes(value);
1200 break;
1201 case 5:
1202 writeVarint64FiveBytes(value);
1203 break;
1204 case 6:
1205 writeVarint64SixBytes(value);
1206 break;
1207 case 7:
1208 writeVarint64SevenBytes(value);
1209 break;
1210 case 8:
1211 writeVarint64EightBytes(value);
1212 break;
1213 case 9:
1214 writeVarint64NineBytes(value);
1215 break;
1216 case 10:
1217 writeVarint64TenBytes(value);
1218 break;
1219 }
1220 }
1221
1222 private void writeVarint64OneByte(long value) {
1223 buffer[pos--] = (byte) value;
1224 }
1225
1226 private void writeVarint64TwoBytes(long value) {
1227 buffer[pos--] = (byte) (value >>> 7);
1228 buffer[pos--] = (byte) (((int) value & 0x7F) | 0x80);
1229 }
1230
1231 private void writeVarint64ThreeBytes(long value) {
1232 buffer[pos--] = (byte) (((int) value) >>> 14);
1233 buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
1234 buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
1235 }
1236
1237 private void writeVarint64FourBytes(long value) {
1238 buffer[pos--] = (byte) (value >>> 21);
1239 buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
1240 buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
1241 buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
1242 }
1243
1244 private void writeVarint64FiveBytes(long value) {
1245 buffer[pos--] = (byte) (value >>> 28);
1246 buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80);
1247 buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
1248 buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
1249 buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
1250 }
1251
1252 private void writeVarint64SixBytes(long value) {
1253 buffer[pos--] = (byte) (value >>> 35);
1254 buffer[pos--] = (byte) (((value >>> 28) & 0x7F) | 0x80);
1255 buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80);
1256 buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
1257 buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
1258 buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
1259 }
1260
1261 private void writeVarint64SevenBytes(long value) {
1262 buffer[pos--] = (byte) (value >>> 42);
1263 buffer[pos--] = (byte) (((value >>> 35) & 0x7F) | 0x80);
1264 buffer[pos--] = (byte) (((value >>> 28) & 0x7F) | 0x80);
1265 buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80);
1266 buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
1267 buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
1268 buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
1269 }
1270
1271 private void writeVarint64EightBytes(long value) {
1272 buffer[pos--] = (byte) (value >>> 49);
1273 buffer[pos--] = (byte) (((value >>> 42) & 0x7F) | 0x80);
1274 buffer[pos--] = (byte) (((value >>> 35) & 0x7F) | 0x80);
1275 buffer[pos--] = (byte) (((value >>> 28) & 0x7F) | 0x80);
1276 buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80);
1277 buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
1278 buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
1279 buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
1280 }
1281
1282 private void writeVarint64NineBytes(long value) {
1283 buffer[pos--] = (byte) (value >>> 56);
1284 buffer[pos--] = (byte) (((value >>> 49) & 0x7F) | 0x80);
1285 buffer[pos--] = (byte) (((value >>> 42) & 0x7F) | 0x80);
1286 buffer[pos--] = (byte) (((value >>> 35) & 0x7F) | 0x80);
1287 buffer[pos--] = (byte) (((value >>> 28) & 0x7F) | 0x80);
1288 buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80);
1289 buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
1290 buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
1291 buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
1292 }
1293
1294 private void writeVarint64TenBytes(long value) {
1295 buffer[pos--] = (byte) (value >>> 63);
1296 buffer[pos--] = (byte) (((value >>> 56) & 0x7F) | 0x80);
1297 buffer[pos--] = (byte) (((value >>> 49) & 0x7F) | 0x80);
1298 buffer[pos--] = (byte) (((value >>> 42) & 0x7F) | 0x80);
1299 buffer[pos--] = (byte) (((value >>> 35) & 0x7F) | 0x80);
1300 buffer[pos--] = (byte) (((value >>> 28) & 0x7F) | 0x80);
1301 buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80);
1302 buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
1303 buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
1304 buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
1305 }
1306
1307 @Override
1308 void writeFixed32(int value) {
1309 buffer[pos--] = (byte) ((value >> 24) & 0xFF);
1310 buffer[pos--] = (byte) ((value >> 16) & 0xFF);
1311 buffer[pos--] = (byte) ((value >> 8) & 0xFF);
1312 buffer[pos--] = (byte) (value & 0xFF);
1313 }
1314
1315 @Override
1316 void writeFixed64(long value) {
1317 buffer[pos--] = (byte) ((int) (value >> 56) & 0xFF);
1318 buffer[pos--] = (byte) ((int) (value >> 48) & 0xFF);
1319 buffer[pos--] = (byte) ((int) (value >> 40) & 0xFF);
1320 buffer[pos--] = (byte) ((int) (value >> 32) & 0xFF);
1321 buffer[pos--] = (byte) ((int) (value >> 24) & 0xFF);
1322 buffer[pos--] = (byte) ((int) (value >> 16) & 0xFF);
1323 buffer[pos--] = (byte) ((int) (value >> 8) & 0xFF);
1324 buffer[pos--] = (byte) ((int) (value) & 0xFF);
1325 }
1326
1327 @Override
1328 void writeString(String in) {
1329 // Request enough space to write the ASCII string.
1330 requireSpace(in.length());
1331
1332 // We know the buffer is big enough...
1333 int i = in.length() - 1;
1334 // Set pos to the start of the ASCII string.
1335 pos -= i;
1336 // Designed to take advantage of
1337 // https://wiki.openjdk.java.net/display/HotSpotInternals/RangeCheckElimination
1338 for (char c; i >= 0 && (c = in.charAt(i)) < 0x80; i--) {
1339 buffer[pos + i] = (byte) c;
1340 }
1341 if (i == -1) {
1342 // Move pos past the String.
1343 pos -= 1;
1344 return;
1345 }
1346 pos += i;
1347 for (char c; i >= 0; i--) {
1348 c = in.charAt(i);
1349 if (c < 0x80 && pos > offsetMinusOne) {
1350 buffer[pos--] = (byte) c;
1351 } else if (c < 0x800 && pos > offset) { // 11 bits, two UTF-8 bytes
1352 buffer[pos--] = (byte) (0x80 | (0x3F & c));
1353 buffer[pos--] = (byte) ((0xF << 6) | (c >>> 6));
1354 } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c)
1355 && pos > (offset + 1)) {
1356 // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
1357 buffer[pos--] = (byte) (0x80 | (0x3F & c));
1358 buffer[pos--] = (byte) (0x80 | (0x3F & (c >>> 6)));
1359 buffer[pos--] = (byte) ((0xF << 5) | (c >>> 12));
1360 } else if (pos > (offset + 2)) {
1361 // Minimum code point represented by a surrogate pair is 0x10000, 17 bits,
1362 // four UTF-8 bytes
1363 char high = 0;
1364 if (i == 0 || !Character.isSurrogatePair(high = in.charAt(i - 1), c)) {
1365 throw new Utf8.UnpairedSurrogateException(i - 1, i);
1366 }
1367 i--;
1368 int codePoint = Character.toCodePoint(high, c);
1369 buffer[pos--] = (byte) (0x80 | (0x3F & codePoint));
1370 buffer[pos--] = (byte) (0x80 | (0x3F & (codePoint >>> 6)));
1371 buffer[pos--] = (byte) (0x80 | (0x3F & (codePoint >>> 12)));
1372 buffer[pos--] = (byte) ((0xF << 4) | (codePoint >>> 18));
1373 } else {
1374 // Buffer is full - allocate a new one and revisit the current character.
1375 requireSpace(i);
1376 i++;
1377 }
1378 }
1379 }
1380
1381 @Override
1382 public void write(byte value) {
1383 buffer[pos--] = value;
1384 }
1385
1386 @Override
1387 public void write(byte[] value, int offset, int length) {
1388 if (spaceLeft() < length) {
1389 nextBuffer(length);
1390 }
1391
1392 pos -= length;
1393 System.arraycopy(value, offset, buffer, pos + 1, length);
1394 }
1395
1396 @Override
1397 public void writeLazy(byte[] value, int offset, int length) {
1398 if (spaceLeft() < length) {
1399 // We consider the value to be immutable (likely the internals of a ByteString). Just
1400 // wrap it in a Netty buffer and add it to the output buffer.
1401 totalDoneBytes += length;
1402 buffers.addFirst(AllocatedBuffer.wrap(value, offset, length));
1403
1404 // Advance the writer to the next buffer.
1405 // TODO(nathanmittler): Consider slicing if space available above some threshold.
1406 nextBuffer();
1407 return;
1408 }
1409
1410 pos -= length;
1411 System.arraycopy(value, offset, buffer, pos + 1, length);
1412 }
1413
1414 @Override
1415 public void write(ByteBuffer value) {
1416 int length = value.remaining();
1417 if (spaceLeft() < length) {
1418 nextBuffer(length);
1419 }
1420
1421 pos -= length;
1422 value.get(buffer, pos + 1, length);
1423 }
1424
1425 @Override
1426 public void writeLazy(ByteBuffer value) {
1427 int length = value.remaining();
1428 if (spaceLeft() < length) {
1429 // We consider the value to be immutable (likely the internals of a ByteString). Just
1430 // wrap it in a Netty buffer and add it to the output buffer.
1431 totalDoneBytes += length;
1432 buffers.addFirst(AllocatedBuffer.wrap(value));
1433
1434 // Advance the writer to the next buffer.
1435 // TODO(nathanmittler): Consider slicing if space available above some threshold.
1436 nextBuffer();
1437 }
1438
1439 pos -= length;
1440 value.get(buffer, pos + 1, length);
1441 }
1442
1443 @Override
1444 void requireSpace(int size) {
1445 if (spaceLeft() < size) {
1446 nextBuffer(size);
1447 }
1448 }
1449 }
1450
1451 /** Writer that uses unsafe operations on a target array. */
1452 private static final class UnsafeHeapWriter extends BinaryWriter {
1453 private AllocatedBuffer allocatedBuffer;
1454 private byte[] buffer;
1455 private long offset;
1456 private long limit;
1457 private long offsetMinusOne;
1458 private long limitMinusOne;
1459 private long pos;
1460
1461 UnsafeHeapWriter(BufferAllocator alloc, int chunkSize) {
1462 super(alloc, chunkSize);
1463 nextBuffer();
1464 }
1465
1466 /** Indicates whether the required unsafe operations are supported on this platform. */
1467 static boolean isSupported() {
1468 return UnsafeUtil.hasUnsafeArrayOperations();
1469 }
1470
1471 @Override
1472 void finishCurrentBuffer() {
1473 if (allocatedBuffer != null) {
1474 totalDoneBytes += bytesWrittenToCurrentBuffer();
1475 allocatedBuffer.position((arrayPos() - allocatedBuffer.arrayOffset()) + 1);
1476 allocatedBuffer = null;
1477 pos = 0;
1478 limitMinusOne = 0;
1479 }
1480 }
1481
1482 private int arrayPos() {
1483 return (int) pos;
1484 }
1485
1486 private void nextBuffer() {
1487 nextBuffer(newHeapBuffer());
1488 }
1489
1490 private void nextBuffer(int capacity) {
1491 nextBuffer(newHeapBuffer(capacity));
1492 }
1493
1494 private void nextBuffer(AllocatedBuffer allocatedBuffer) {
1495 if (!allocatedBuffer.hasArray()) {
1496 throw new RuntimeException("Allocator returned non-heap buffer");
1497 }
1498
1499 finishCurrentBuffer();
1500 buffers.addFirst(allocatedBuffer);
1501
1502 this.allocatedBuffer = allocatedBuffer;
1503 this.buffer = allocatedBuffer.array();
1504 int arrayOffset = allocatedBuffer.arrayOffset();
1505 this.limit = (long) arrayOffset + allocatedBuffer.limit();
1506 this.offset = (long) arrayOffset + allocatedBuffer.position();
1507 this.offsetMinusOne = offset - 1;
1508 this.limitMinusOne = limit - 1;
1509 this.pos = limitMinusOne;
1510 }
1511
1512 @Override
1513 public int getTotalBytesWritten() {
1514 return totalDoneBytes + bytesWrittenToCurrentBuffer();
1515 }
1516
1517 int bytesWrittenToCurrentBuffer() {
1518 return (int) (limitMinusOne - pos);
1519 }
1520
1521 int spaceLeft() {
1522 return (int) (pos - offsetMinusOne);
1523 }
1524
1525 @Override
1526 public void writeUInt32(int fieldNumber, int value) {
1527 requireSpace(MAX_VARINT32_SIZE * 2);
1528 writeVarint32(value);
1529 writeTag(fieldNumber, WIRETYPE_VARINT);
1530 }
1531
1532 @Override
1533 public void writeInt32(int fieldNumber, int value) {
1534 requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
1535 writeInt32(value);
1536 writeTag(fieldNumber, WIRETYPE_VARINT);
1537 }
1538
1539 @Override
1540 public void writeSInt32(int fieldNumber, int value) {
1541 requireSpace(MAX_VARINT32_SIZE * 2);
1542 writeSInt32(value);
1543 writeTag(fieldNumber, WIRETYPE_VARINT);
1544 }
1545
1546 @Override
1547 public void writeFixed32(int fieldNumber, int value) {
1548 requireSpace(MAX_VARINT32_SIZE + FIXED32_SIZE);
1549 writeFixed32(value);
1550 writeTag(fieldNumber, WIRETYPE_FIXED32);
1551 }
1552
1553 @Override
1554 public void writeUInt64(int fieldNumber, long value) {
1555 requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
1556 writeVarint64(value);
1557 writeTag(fieldNumber, WIRETYPE_VARINT);
1558 }
1559
1560 @Override
1561 public void writeSInt64(int fieldNumber, long value) {
1562 requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
1563 writeSInt64(value);
1564 writeTag(fieldNumber, WIRETYPE_VARINT);
1565 }
1566
1567 @Override
1568 public void writeFixed64(int fieldNumber, long value) {
1569 requireSpace(MAX_VARINT32_SIZE + FIXED64_SIZE);
1570 writeFixed64(value);
1571 writeTag(fieldNumber, WIRETYPE_FIXED64);
1572 }
1573
1574 @Override
1575 public void writeBool(int fieldNumber, boolean value) {
1576 requireSpace(MAX_VARINT32_SIZE + 1);
1577 write((byte) (value ? 1 : 0));
1578 writeTag(fieldNumber, WIRETYPE_VARINT);
1579 }
1580
1581 @Override
1582 public void writeString(int fieldNumber, String value) {
1583 int prevBytes = getTotalBytesWritten();
1584 writeString(value);
1585 int length = getTotalBytesWritten() - prevBytes;
1586 requireSpace(2 * MAX_VARINT32_SIZE);
1587 writeVarint32(length);
1588 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
1589 }
1590
1591 @Override
1592 public void writeBytes(int fieldNumber, ByteString value) {
1593 try {
1594 value.writeToReverse(this);
1595 } catch (IOException e) {
1596 // Should never happen since the writer does not throw.
1597 throw new RuntimeException(e);
1598 }
1599
1600 requireSpace(MAX_VARINT32_SIZE * 2);
1601 writeVarint32(value.size());
1602 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
1603 }
1604
1605 @Override
1606 public void writeMessage(int fieldNumber, Object value) throws IOException {
1607 int prevBytes = getTotalBytesWritten();
1608 Protobuf.getInstance().writeTo(value, this);
1609 int length = getTotalBytesWritten() - prevBytes;
1610 requireSpace(MAX_VARINT32_SIZE * 2);
1611 writeVarint32(length);
1612 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
1613 }
1614
1615 @Override
1616 public void writeMessage(int fieldNumber, Object value, Schema schema) throws IOException {
1617 int prevBytes = getTotalBytesWritten();
1618 schema.writeTo(value, this);
1619 int length = getTotalBytesWritten() - prevBytes;
1620 requireSpace(MAX_VARINT32_SIZE * 2);
1621 writeVarint32(length);
1622 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
1623 }
1624
1625 @Override
1626 public void writeGroup(int fieldNumber, Object value) throws IOException {
1627 writeTag(fieldNumber, WIRETYPE_END_GROUP);
1628 Protobuf.getInstance().writeTo(value, this);
1629 writeTag(fieldNumber, WIRETYPE_START_GROUP);
1630 }
1631
1632 @Override
1633 public void writeGroup(int fieldNumber, Object value, Schema schema) throws IOException {
1634 writeTag(fieldNumber, WIRETYPE_END_GROUP);
1635 schema.writeTo(value, this);
1636 writeTag(fieldNumber, WIRETYPE_START_GROUP);
1637 }
1638
1639 @Override
1640 public void writeStartGroup(int fieldNumber) {
1641 writeTag(fieldNumber, WIRETYPE_START_GROUP);
1642 }
1643
1644 @Override
1645 public void writeEndGroup(int fieldNumber) {
1646 writeTag(fieldNumber, WIRETYPE_END_GROUP);
1647 }
1648
1649 @Override
1650 void writeInt32(int value) {
1651 if (value >= 0) {
1652 writeVarint32(value);
1653 } else {
1654 writeVarint64(value);
1655 }
1656 }
1657
1658 @Override
1659 void writeSInt32(int value) {
1660 writeVarint32(CodedOutputStream.encodeZigZag32(value));
1661 }
1662
1663 @Override
1664 void writeSInt64(long value) {
1665 writeVarint64(CodedOutputStream.encodeZigZag64(value));
1666 }
1667
1668 @Override
1669 void writeBool(boolean value) {
1670 write((byte) (value ? 1 : 0));
1671 }
1672
1673 @Override
1674 void writeTag(int fieldNumber, int wireType) {
1675 writeVarint32(WireFormat.makeTag(fieldNumber, wireType));
1676 }
1677
1678 @Override
1679 void writeVarint32(int value) {
1680 if ((value & (~0 << 7)) == 0) {
1681 writeVarint32OneByte(value);
1682 } else if ((value & (~0 << 14)) == 0) {
1683 writeVarint32TwoBytes(value);
1684 } else if ((value & (~0 << 21)) == 0) {
1685 writeVarint32ThreeBytes(value);
1686 } else if ((value & (~0 << 28)) == 0) {
1687 writeVarint32FourBytes(value);
1688 } else {
1689 writeVarint32FiveBytes(value);
1690 }
1691 }
1692
1693 private void writeVarint32OneByte(int value) {
1694 UnsafeUtil.putByte(buffer, pos--, (byte) value);
1695 }
1696
1697 private void writeVarint32TwoBytes(int value) {
1698 UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 7));
1699 UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
1700 }
1701
1702 private void writeVarint32ThreeBytes(int value) {
1703 UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 14));
1704 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
1705 UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
1706 }
1707
1708 private void writeVarint32FourBytes(int value) {
1709 UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 21));
1710 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
1711 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
1712 UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
1713 }
1714
1715 private void writeVarint32FiveBytes(int value) {
1716 UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 28));
1717 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
1718 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
1719 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
1720 UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
1721 }
1722
1723 @Override
1724 void writeVarint64(long value) {
1725 switch (computeUInt64SizeNoTag(value)) {
1726 case 1:
1727 writeVarint64OneByte(value);
1728 break;
1729 case 2:
1730 writeVarint64TwoBytes(value);
1731 break;
1732 case 3:
1733 writeVarint64ThreeBytes(value);
1734 break;
1735 case 4:
1736 writeVarint64FourBytes(value);
1737 break;
1738 case 5:
1739 writeVarint64FiveBytes(value);
1740 break;
1741 case 6:
1742 writeVarint64SixBytes(value);
1743 break;
1744 case 7:
1745 writeVarint64SevenBytes(value);
1746 break;
1747 case 8:
1748 writeVarint64EightBytes(value);
1749 break;
1750 case 9:
1751 writeVarint64NineBytes(value);
1752 break;
1753 case 10:
1754 writeVarint64TenBytes(value);
1755 break;
1756 }
1757 }
1758
1759 private void writeVarint64OneByte(long value) {
1760 UnsafeUtil.putByte(buffer, pos--, (byte) value);
1761 }
1762
1763 private void writeVarint64TwoBytes(long value) {
1764 UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 7));
1765 UnsafeUtil.putByte(buffer, pos--, (byte) (((int) value & 0x7F) | 0x80));
1766 }
1767
1768 private void writeVarint64ThreeBytes(long value) {
1769 UnsafeUtil.putByte(buffer, pos--, (byte) (((int) value) >>> 14));
1770 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
1771 UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
1772 }
1773
1774 private void writeVarint64FourBytes(long value) {
1775 UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 21));
1776 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
1777 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
1778 UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
1779 }
1780
1781 private void writeVarint64FiveBytes(long value) {
1782 UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 28));
1783 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
1784 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
1785 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
1786 UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
1787 }
1788
1789 private void writeVarint64SixBytes(long value) {
1790 UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 35));
1791 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
1792 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
1793 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
1794 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
1795 UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
1796 }
1797
1798 private void writeVarint64SevenBytes(long value) {
1799 UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 42));
1800 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 35) & 0x7F) | 0x80));
1801 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
1802 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
1803 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
1804 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
1805 UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
1806 }
1807
1808 private void writeVarint64EightBytes(long value) {
1809 UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 49));
1810 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 42) & 0x7F) | 0x80));
1811 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 35) & 0x7F) | 0x80));
1812 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
1813 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
1814 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
1815 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
1816 UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
1817 }
1818
1819 private void writeVarint64NineBytes(long value) {
1820 UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 56));
1821 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 49) & 0x7F) | 0x80));
1822 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 42) & 0x7F) | 0x80));
1823 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 35) & 0x7F) | 0x80));
1824 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
1825 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
1826 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
1827 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
1828 UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
1829 }
1830
1831 private void writeVarint64TenBytes(long value) {
1832 UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 63));
1833 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 56) & 0x7F) | 0x80));
1834 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 49) & 0x7F) | 0x80));
1835 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 42) & 0x7F) | 0x80));
1836 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 35) & 0x7F) | 0x80));
1837 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
1838 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
1839 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
1840 UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
1841 UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
1842 }
1843
1844 @Override
1845 void writeFixed32(int value) {
1846 UnsafeUtil.putByte(buffer, pos--, (byte) ((value >> 24) & 0xFF));
1847 UnsafeUtil.putByte(buffer, pos--, (byte) ((value >> 16) & 0xFF));
1848 UnsafeUtil.putByte(buffer, pos--, (byte) ((value >> 8) & 0xFF));
1849 UnsafeUtil.putByte(buffer, pos--, (byte) (value & 0xFF));
1850 }
1851
1852 @Override
1853 void writeFixed64(long value) {
1854 UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 56) & 0xFF));
1855 UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 48) & 0xFF));
1856 UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 40) & 0xFF));
1857 UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 32) & 0xFF));
1858 UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 24) & 0xFF));
1859 UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 16) & 0xFF));
1860 UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 8) & 0xFF));
1861 UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value) & 0xFF));
1862 }
1863
1864 @Override
1865 void writeString(String in) {
1866 // Request enough space to write the ASCII string.
1867 requireSpace(in.length());
1868
1869 // We know the buffer is big enough...
1870 int i = in.length() - 1;
1871 // Set pos to the start of the ASCII string.
1872 // pos -= i;
1873 // Designed to take advantage of
1874 // https://wiki.openjdk.java.net/display/HotSpotInternals/RangeCheckElimination
1875 for (char c; i >= 0 && (c = in.charAt(i)) < 0x80; i--) {
1876 UnsafeUtil.putByte(buffer, pos--, (byte) c);
1877 }
1878 if (i == -1) {
1879 // Move pos past the String.
1880 return;
1881 }
1882 for (char c; i >= 0; i--) {
1883 c = in.charAt(i);
1884 if (c < 0x80 && pos > offsetMinusOne) {
1885 UnsafeUtil.putByte(buffer, pos--, (byte) c);
1886 } else if (c < 0x800 && pos > offset) { // 11 bits, two UTF-8 bytes
1887 UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & c)));
1888 UnsafeUtil.putByte(buffer, pos--, (byte) ((0xF << 6) | (c >>> 6)));
1889 } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c)
1890 && pos > offset + 1) {
1891 // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
1892 UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & c)));
1893 UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & (c >>> 6))));
1894 UnsafeUtil.putByte(buffer, pos--, (byte) ((0xF << 5) | (c >>> 12)));
1895 } else if (pos > offset + 2) {
1896 // Minimum code point represented by a surrogate pair is 0x10000, 17 bits,
1897 // four UTF-8 bytes
1898 final char high;
1899 if (i == 0 || !Character.isSurrogatePair(high = in.charAt(i - 1), c)) {
1900 throw new Utf8.UnpairedSurrogateException(i - 1, i);
1901 }
1902 i--;
1903 int codePoint = Character.toCodePoint(high, c);
1904 UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & codePoint)));
1905 UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
1906 UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
1907 UnsafeUtil.putByte(buffer, pos--, (byte) ((0xF << 4) | (codePoint >>> 18)));
1908 } else {
1909 // Buffer is full - allocate a new one and revisit the current character.
1910 requireSpace(i);
1911 i++;
1912 }
1913 }
1914 }
1915
1916 @Override
1917 public void write(byte value) {
1918 UnsafeUtil.putByte(buffer, pos--, value);
1919 }
1920
1921 @Override
1922 public void write(byte[] value, int offset, int length) {
1923 if (offset < 0 || offset + length > value.length) {
1924 throw new ArrayIndexOutOfBoundsException(
1925 String.format("value.length=%d, offset=%d, length=%d", value.length, offset, length));
1926 }
1927 requireSpace(length);
1928
1929 pos -= length;
1930 System.arraycopy(value, offset, buffer, arrayPos() + 1, length);
1931 }
1932
1933 @Override
1934 public void writeLazy(byte[] value, int offset, int length) {
1935 if (offset < 0 || offset + length > value.length) {
1936 throw new ArrayIndexOutOfBoundsException(
1937 String.format("value.length=%d, offset=%d, length=%d", value.length, offset, length));
1938 }
1939 if (spaceLeft() < length) {
1940 // We consider the value to be immutable (likely the internals of a ByteString). Just
1941 // wrap it in a Netty buffer and add it to the output buffer.
1942 totalDoneBytes += length;
1943 buffers.addFirst(AllocatedBuffer.wrap(value, offset, length));
1944
1945 // Advance the writer to the next buffer.
1946 // TODO(nathanmittler): Consider slicing if space available above some threshold.
1947 nextBuffer();
1948 return;
1949 }
1950
1951 pos -= length;
1952 System.arraycopy(value, offset, buffer, arrayPos() + 1, length);
1953 }
1954
1955 @Override
1956 public void write(ByteBuffer value) {
1957 int length = value.remaining();
1958 requireSpace(length);
1959
1960 pos -= length;
1961 value.get(buffer, arrayPos() + 1, length);
1962 }
1963
1964 @Override
1965 public void writeLazy(ByteBuffer value) {
1966 int length = value.remaining();
1967 if (spaceLeft() < length) {
1968 // We consider the value to be immutable (likely the internals of a ByteString). Just
1969 // wrap it in a Netty buffer and add it to the output buffer.
1970 totalDoneBytes += length;
1971 buffers.addFirst(AllocatedBuffer.wrap(value));
1972
1973 // Advance the writer to the next buffer.
1974 // TODO(nathanmittler): Consider slicing if space available above some threshold.
1975 nextBuffer();
1976 }
1977
1978 pos -= length;
1979 value.get(buffer, arrayPos() + 1, length);
1980 }
1981
1982 @Override
1983 void requireSpace(int size) {
1984 if (spaceLeft() < size) {
1985 nextBuffer(size);
1986 }
1987 }
1988 }
1989
1990 /** Writer that uses safe operations on a target {@link ByteBuffer}. */
1991 private static final class SafeDirectWriter extends BinaryWriter {
1992 private ByteBuffer buffer;
1993 private int limitMinusOne;
1994 private int pos;
1995
1996 SafeDirectWriter(BufferAllocator alloc, int chunkSize) {
1997 super(alloc, chunkSize);
1998 nextBuffer();
1999 }
2000
2001 private void nextBuffer() {
2002 nextBuffer(newDirectBuffer());
2003 }
2004
2005 private void nextBuffer(int capacity) {
2006 nextBuffer(newDirectBuffer(capacity));
2007 }
2008
2009 private void nextBuffer(AllocatedBuffer allocatedBuffer) {
2010 if (!allocatedBuffer.hasNioBuffer()) {
2011 throw new RuntimeException("Allocated buffer does not have NIO buffer");
2012 }
2013 ByteBuffer nioBuffer = allocatedBuffer.nioBuffer();
2014 if (!nioBuffer.isDirect()) {
2015 throw new RuntimeException("Allocator returned non-direct buffer");
2016 }
2017
2018 finishCurrentBuffer();
2019 buffers.addFirst(allocatedBuffer);
2020
2021 buffer = nioBuffer;
2022 buffer.limit(buffer.capacity());
2023 buffer.position(0);
2024 // Set byte order to little endian for fast writing of fixed 32/64.
2025 buffer.order(ByteOrder.LITTLE_ENDIAN);
2026
2027 limitMinusOne = buffer.limit() - 1;
2028 pos = limitMinusOne;
2029 }
2030
2031 @Override
2032 public int getTotalBytesWritten() {
2033 return totalDoneBytes + bytesWrittenToCurrentBuffer();
2034 }
2035
2036 private int bytesWrittenToCurrentBuffer() {
2037 return limitMinusOne - pos;
2038 }
2039
2040 private int spaceLeft() {
2041 return pos + 1;
2042 }
2043
2044 @Override
2045 void finishCurrentBuffer() {
2046 if (buffer != null) {
2047 totalDoneBytes += bytesWrittenToCurrentBuffer();
2048 // Update the indices on the netty buffer.
2049 buffer.position(pos + 1);
2050 buffer = null;
2051 pos = 0;
2052 limitMinusOne = 0;
2053 }
2054 }
2055
2056 @Override
2057 public void writeUInt32(int fieldNumber, int value) {
2058 requireSpace(MAX_VARINT32_SIZE * 2);
2059 writeVarint32(value);
2060 writeTag(fieldNumber, WIRETYPE_VARINT);
2061 }
2062
2063 @Override
2064 public void writeInt32(int fieldNumber, int value) {
2065 requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
2066 writeInt32(value);
2067 writeTag(fieldNumber, WIRETYPE_VARINT);
2068 }
2069
2070 @Override
2071 public void writeSInt32(int fieldNumber, int value) {
2072 requireSpace(MAX_VARINT32_SIZE * 2);
2073 writeSInt32(value);
2074 writeTag(fieldNumber, WIRETYPE_VARINT);
2075 }
2076
2077 @Override
2078 public void writeFixed32(int fieldNumber, int value) {
2079 requireSpace(MAX_VARINT32_SIZE + FIXED32_SIZE);
2080 writeFixed32(value);
2081 writeTag(fieldNumber, WIRETYPE_FIXED32);
2082 }
2083
2084 @Override
2085 public void writeUInt64(int fieldNumber, long value) {
2086 requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
2087 writeVarint64(value);
2088 writeTag(fieldNumber, WIRETYPE_VARINT);
2089 }
2090
2091 @Override
2092 public void writeSInt64(int fieldNumber, long value) {
2093 requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
2094 writeSInt64(value);
2095 writeTag(fieldNumber, WIRETYPE_VARINT);
2096 }
2097
2098 @Override
2099 public void writeFixed64(int fieldNumber, long value) {
2100 requireSpace(MAX_VARINT32_SIZE + FIXED64_SIZE);
2101 writeFixed64(value);
2102 writeTag(fieldNumber, WIRETYPE_FIXED64);
2103 }
2104
2105 @Override
2106 public void writeBool(int fieldNumber, boolean value) {
2107 requireSpace(MAX_VARINT32_SIZE + 1);
2108 write((byte) (value ? 1 : 0));
2109 writeTag(fieldNumber, WIRETYPE_VARINT);
2110 }
2111
2112 @Override
2113 public void writeString(int fieldNumber, String value) {
2114 int prevBytes = getTotalBytesWritten();
2115 writeString(value);
2116 int length = getTotalBytesWritten() - prevBytes;
2117 requireSpace(2 * MAX_VARINT32_SIZE);
2118 writeVarint32(length);
2119 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
2120 }
2121
2122 @Override
2123 public void writeBytes(int fieldNumber, ByteString value) {
2124 try {
2125 value.writeToReverse(this);
2126 } catch (IOException e) {
2127 // Should never happen since the writer does not throw.
2128 throw new RuntimeException(e);
2129 }
2130
2131 requireSpace(MAX_VARINT32_SIZE * 2);
2132 writeVarint32(value.size());
2133 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
2134 }
2135
2136 @Override
2137 public void writeMessage(int fieldNumber, Object value) throws IOException {
2138 int prevBytes = getTotalBytesWritten();
2139 Protobuf.getInstance().writeTo(value, this);
2140 int length = getTotalBytesWritten() - prevBytes;
2141 requireSpace(MAX_VARINT32_SIZE * 2);
2142 writeVarint32(length);
2143 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
2144 }
2145
2146 @Override
2147 public void writeMessage(int fieldNumber, Object value, Schema schema) throws IOException {
2148 int prevBytes = getTotalBytesWritten();
2149 schema.writeTo(value, this);
2150 int length = getTotalBytesWritten() - prevBytes;
2151 requireSpace(MAX_VARINT32_SIZE * 2);
2152 writeVarint32(length);
2153 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
2154 }
2155
2156 @Deprecated
2157 @Override
2158 public void writeGroup(int fieldNumber, Object value) throws IOException {
2159 writeTag(fieldNumber, WIRETYPE_END_GROUP);
2160 Protobuf.getInstance().writeTo(value, this);
2161 writeTag(fieldNumber, WIRETYPE_START_GROUP);
2162 }
2163
2164 @Override
2165 public void writeGroup(int fieldNumber, Object value, Schema schema) throws IOException {
2166 writeTag(fieldNumber, WIRETYPE_END_GROUP);
2167 schema.writeTo(value, this);
2168 writeTag(fieldNumber, WIRETYPE_START_GROUP);
2169 }
2170
2171 @Deprecated
2172 @Override
2173 public void writeStartGroup(int fieldNumber) {
2174 writeTag(fieldNumber, WIRETYPE_START_GROUP);
2175 }
2176
2177 @Deprecated
2178 @Override
2179 public void writeEndGroup(int fieldNumber) {
2180 writeTag(fieldNumber, WIRETYPE_END_GROUP);
2181 }
2182
2183 @Override
2184 void writeInt32(int value) {
2185 if (value >= 0) {
2186 writeVarint32(value);
2187 } else {
2188 writeVarint64(value);
2189 }
2190 }
2191
2192 @Override
2193 void writeSInt32(int value) {
2194 writeVarint32(CodedOutputStream.encodeZigZag32(value));
2195 }
2196
2197 @Override
2198 void writeSInt64(long value) {
2199 writeVarint64(CodedOutputStream.encodeZigZag64(value));
2200 }
2201
2202 @Override
2203 void writeBool(boolean value) {
2204 write((byte) (value ? 1 : 0));
2205 }
2206
2207 @Override
2208 void writeTag(int fieldNumber, int wireType) {
2209 writeVarint32(WireFormat.makeTag(fieldNumber, wireType));
2210 }
2211
2212 @Override
2213 void writeVarint32(int value) {
2214 if ((value & (~0 << 7)) == 0) {
2215 writeVarint32OneByte(value);
2216 } else if ((value & (~0 << 14)) == 0) {
2217 writeVarint32TwoBytes(value);
2218 } else if ((value & (~0 << 21)) == 0) {
2219 writeVarint32ThreeBytes(value);
2220 } else if ((value & (~0 << 28)) == 0) {
2221 writeVarint32FourBytes(value);
2222 } else {
2223 writeVarint32FiveBytes(value);
2224 }
2225 }
2226
2227 private void writeVarint32OneByte(int value) {
2228 buffer.put(pos--, (byte) value);
2229 }
2230
2231 private void writeVarint32TwoBytes(int value) {
2232 // Byte order is little-endian.
2233 pos -= 2;
2234 buffer.putShort(pos + 1, (short) (((value & (0x7F << 7)) << 1) | ((value & 0x7F) | 0x80)));
2235 }
2236
2237 private void writeVarint32ThreeBytes(int value) {
2238 // Byte order is little-endian.
2239 pos -= 3;
2240 buffer.putInt(
2241 pos,
2242 ((value & (0x7F << 14)) << 10)
2243 | (((value & (0x7F << 7)) | (0x80 << 7)) << 9)
2244 | ((value & 0x7F) | 0x80) << 8);
2245 }
2246
2247 private void writeVarint32FourBytes(int value) {
2248 // Byte order is little-endian.
2249 pos -= 4;
2250 buffer.putInt(
2251 pos + 1,
2252 ((value & (0x7F << 21)) << 3)
2253 | (((value & (0x7F << 14)) | (0x80 << 14)) << 2)
2254 | (((value & (0x7F << 7)) | (0x80 << 7)) << 1)
2255 | ((value & 0x7F) | 0x80));
2256 }
2257
2258 private void writeVarint32FiveBytes(int value) {
2259 // Byte order is little-endian.
2260 buffer.put(pos--, (byte) (value >>> 28));
2261 pos -= 4;
2262 buffer.putInt(
2263 pos + 1,
2264 ((((value >>> 21) & 0x7F) | 0x80) << 24)
2265 | ((((value >>> 14) & 0x7F) | 0x80) << 16)
2266 | ((((value >>> 7) & 0x7F) | 0x80) << 8)
2267 | ((value & 0x7F) | 0x80));
2268 }
2269
2270 @Override
2271 void writeVarint64(long value) {
2272 switch (computeUInt64SizeNoTag(value)) {
2273 case 1:
2274 writeVarint64OneByte(value);
2275 break;
2276 case 2:
2277 writeVarint64TwoBytes(value);
2278 break;
2279 case 3:
2280 writeVarint64ThreeBytes(value);
2281 break;
2282 case 4:
2283 writeVarint64FourBytes(value);
2284 break;
2285 case 5:
2286 writeVarint64FiveBytes(value);
2287 break;
2288 case 6:
2289 writeVarint64SixBytes(value);
2290 break;
2291 case 7:
2292 writeVarint64SevenBytes(value);
2293 break;
2294 case 8:
2295 writeVarint64EightBytes(value);
2296 break;
2297 case 9:
2298 writeVarint64NineBytes(value);
2299 break;
2300 case 10:
2301 writeVarint64TenBytes(value);
2302 break;
2303 }
2304 }
2305
2306 private void writeVarint64OneByte(long value) {
2307 writeVarint32OneByte((int) value);
2308 }
2309
2310 private void writeVarint64TwoBytes(long value) {
2311 writeVarint32TwoBytes((int) value);
2312 }
2313
2314 private void writeVarint64ThreeBytes(long value) {
2315 writeVarint32ThreeBytes((int) value);
2316 }
2317
2318 private void writeVarint64FourBytes(long value) {
2319 writeVarint32FourBytes((int) value);
2320 }
2321
2322 private void writeVarint64FiveBytes(long value) {
2323 // Byte order is little-endian.
2324 pos -= 5;
2325 buffer.putLong(
2326 pos - 2,
2327 ((value & (0x7FL << 28)) << 28)
2328 | (((value & (0x7F << 21)) | (0x80 << 21)) << 27)
2329 | (((value & (0x7F << 14)) | (0x80 << 14)) << 26)
2330 | (((value & (0x7F << 7)) | (0x80 << 7)) << 25)
2331 | (((value & 0x7F) | 0x80)) << 24);
2332 }
2333
2334 private void writeVarint64SixBytes(long value) {
2335 // Byte order is little-endian.
2336 pos -= 6;
2337 buffer.putLong(
2338 pos - 1,
2339 ((value & (0x7FL << 35)) << 21)
2340 | (((value & (0x7FL << 28)) | (0x80L << 28)) << 20)
2341 | (((value & (0x7F << 21)) | (0x80 << 21)) << 19)
2342 | (((value & (0x7F << 14)) | (0x80 << 14)) << 18)
2343 | (((value & (0x7F << 7)) | (0x80 << 7)) << 17)
2344 | (((value & 0x7F) | 0x80)) << 16);
2345 }
2346
2347 private void writeVarint64SevenBytes(long value) {
2348 // Byte order is little-endian.
2349 pos -= 7;
2350 buffer.putLong(
2351 pos,
2352 ((value & (0x7FL << 42)) << 14)
2353 | (((value & (0x7FL << 35)) | (0x80L << 35)) << 13)
2354 | (((value & (0x7FL << 28)) | (0x80L << 28)) << 12)
2355 | (((value & (0x7F << 21)) | (0x80 << 21)) << 11)
2356 | (((value & (0x7F << 14)) | (0x80 << 14)) << 10)
2357 | (((value & (0x7F << 7)) | (0x80 << 7)) << 9)
2358 | (((value & 0x7F) | 0x80)) << 8);
2359 }
2360
2361 private void writeVarint64EightBytes(long value) {
2362 // Byte order is little-endian.
2363 pos -= 8;
2364 buffer.putLong(
2365 pos + 1,
2366 ((value & (0x7FL << 49)) << 7)
2367 | (((value & (0x7FL << 42)) | (0x80L << 42)) << 6)
2368 | (((value & (0x7FL << 35)) | (0x80L << 35)) << 5)
2369 | (((value & (0x7FL << 28)) | (0x80L << 28)) << 4)
2370 | (((value & (0x7F << 21)) | (0x80 << 21)) << 3)
2371 | (((value & (0x7F << 14)) | (0x80 << 14)) << 2)
2372 | (((value & (0x7F << 7)) | (0x80 << 7)) << 1)
2373 | ((value & 0x7F) | 0x80));
2374 }
2375
2376 private void writeVarint64EightBytesWithSign(long value) {
2377 // Byte order is little-endian.
2378 pos -= 8;
2379 buffer.putLong(
2380 pos + 1,
2381 (((value & (0x7FL << 49)) | (0x80L << 49)) << 7)
2382 | (((value & (0x7FL << 42)) | (0x80L << 42)) << 6)
2383 | (((value & (0x7FL << 35)) | (0x80L << 35)) << 5)
2384 | (((value & (0x7FL << 28)) | (0x80L << 28)) << 4)
2385 | (((value & (0x7F << 21)) | (0x80 << 21)) << 3)
2386 | (((value & (0x7F << 14)) | (0x80 << 14)) << 2)
2387 | (((value & (0x7F << 7)) | (0x80 << 7)) << 1)
2388 | ((value & 0x7F) | 0x80));
2389 }
2390
2391 private void writeVarint64NineBytes(long value) {
2392 buffer.put(pos--, (byte) (value >>> 56));
2393 writeVarint64EightBytesWithSign(value & 0xFFFFFFFFFFFFFFL);
2394 }
2395
2396 private void writeVarint64TenBytes(long value) {
2397 buffer.put(pos--, (byte) (value >>> 63));
2398 buffer.put(pos--, (byte) (((value >>> 56) & 0x7F) | 0x80));
2399 writeVarint64EightBytesWithSign(value & 0xFFFFFFFFFFFFFFL);
2400 }
2401
2402 @Override
2403 void writeFixed32(int value) {
2404 pos -= 4;
2405 buffer.putInt(pos + 1, value);
2406 }
2407
2408 @Override
2409 void writeFixed64(long value) {
2410 pos -= 8;
2411 buffer.putLong(pos + 1, value);
2412 }
2413
2414 @Override
2415 void writeString(String in) {
2416 // Request enough space to write the ASCII string.
2417 requireSpace(in.length());
2418
2419 // We know the buffer is big enough...
2420 int i = in.length() - 1;
2421 pos -= i;
2422 // Designed to take advantage of
2423 // https://wiki.openjdk.java.net/display/HotSpotInternals/RangeCheckElimination
2424 for (char c; i >= 0 && (c = in.charAt(i)) < 0x80; i--) {
2425 buffer.put(pos + i, (byte) c);
2426 }
2427 if (i == -1) {
2428 // Move the position past the ASCII string.
2429 pos -= 1;
2430 return;
2431 }
2432 pos += i;
2433 for (char c; i >= 0; i--) {
2434 c = in.charAt(i);
2435 if (c < 0x80 && pos >= 0) {
2436 buffer.put(pos--, (byte) c);
2437 } else if (c < 0x800 && pos > 0) { // 11 bits, two UTF-8 bytes
2438 buffer.put(pos--, (byte) (0x80 | (0x3F & c)));
2439 buffer.put(pos--, (byte) ((0xF << 6) | (c >>> 6)));
2440 } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && pos > 1) {
2441 // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
2442 buffer.put(pos--, (byte) (0x80 | (0x3F & c)));
2443 buffer.put(pos--, (byte) (0x80 | (0x3F & (c >>> 6))));
2444 buffer.put(pos--, (byte) ((0xF << 5) | (c >>> 12)));
2445 } else if (pos > 2) {
2446 // Minimum code point represented by a surrogate pair is 0x10000, 17 bits,
2447 // four UTF-8 bytes
2448 char high = 0;
2449 if (i == 0 || !Character.isSurrogatePair(high = in.charAt(i - 1), c)) {
2450 throw new Utf8.UnpairedSurrogateException(i - 1, i);
2451 }
2452 i--;
2453 int codePoint = Character.toCodePoint(high, c);
2454 buffer.put(pos--, (byte) (0x80 | (0x3F & codePoint)));
2455 buffer.put(pos--, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
2456 buffer.put(pos--, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
2457 buffer.put(pos--, (byte) ((0xF << 4) | (codePoint >>> 18)));
2458 } else {
2459 // Buffer is full - allocate a new one and revisit the current character.
2460 requireSpace(i);
2461 i++;
2462 }
2463 }
2464 }
2465
2466 @Override
2467 public void write(byte value) {
2468 buffer.put(pos--, value);
2469 }
2470
2471 @Override
2472 public void write(byte[] value, int offset, int length) {
2473 if (spaceLeft() < length) {
2474 nextBuffer(length);
2475 }
2476
2477 pos -= length;
2478 buffer.position(pos + 1);
2479 buffer.put(value, offset, length);
2480 }
2481
2482 @Override
2483 public void writeLazy(byte[] value, int offset, int length) {
2484 if (spaceLeft() < length) {
2485 // We consider the value to be immutable (likely the internals of a ByteString). Just
2486 // wrap it in a Netty buffer and add it to the output buffer.
2487 totalDoneBytes += length;
2488 buffers.addFirst(AllocatedBuffer.wrap(value, offset, length));
2489
2490 // Advance the writer to the next buffer.
2491 // TODO(nathanmittler): Consider slicing if space available above some threshold.
2492 nextBuffer();
2493 return;
2494 }
2495
2496 pos -= length;
2497 buffer.position(pos + 1);
2498 buffer.put(value, offset, length);
2499 }
2500
2501 @Override
2502 public void write(ByteBuffer value) {
2503 int length = value.remaining();
2504 if (spaceLeft() < length) {
2505 nextBuffer(length);
2506 }
2507
2508 pos -= length;
2509 buffer.position(pos + 1);
2510 buffer.put(value);
2511 }
2512
2513 @Override
2514 public void writeLazy(ByteBuffer value) {
2515 int length = value.remaining();
2516 if (spaceLeft() < length) {
2517 // We consider the value to be immutable (likely the internals of a ByteString). Just
2518 // wrap it in a Netty buffer and add it to the output buffer.
2519 totalDoneBytes += length;
2520 buffers.addFirst(AllocatedBuffer.wrap(value));
2521
2522 // Advance the writer to the next buffer.
2523 // TODO(nathanmittler): Consider slicing if space available above some threshold.
2524 nextBuffer();
2525 return;
2526 }
2527
2528 pos -= length;
2529 buffer.position(pos + 1);
2530 buffer.put(value);
2531 }
2532
2533 @Override
2534 void requireSpace(int size) {
2535 if (spaceLeft() < size) {
2536 nextBuffer(size);
2537 }
2538 }
2539 }
2540
2541 /** Writer that uses unsafe operations on a target {@link ByteBuffer}. */
2542 private static final class UnsafeDirectWriter extends BinaryWriter {
2543 private ByteBuffer buffer;
2544 private long bufferOffset;
2545 private long limitMinusOne;
2546 private long pos;
2547
2548 UnsafeDirectWriter(BufferAllocator alloc, int chunkSize) {
2549 super(alloc, chunkSize);
2550 nextBuffer();
2551 }
2552
2553 /** Indicates whether the required unsafe operations are supported on this platform. */
2554 private static boolean isSupported() {
2555 return UnsafeUtil.hasUnsafeByteBufferOperations();
2556 }
2557
2558 private void nextBuffer() {
2559 nextBuffer(newDirectBuffer());
2560 }
2561
2562 private void nextBuffer(int capacity) {
2563 nextBuffer(newDirectBuffer(capacity));
2564 }
2565
2566 private void nextBuffer(AllocatedBuffer allocatedBuffer) {
2567 if (!allocatedBuffer.hasNioBuffer()) {
2568 throw new RuntimeException("Allocated buffer does not have NIO buffer");
2569 }
2570 ByteBuffer nioBuffer = allocatedBuffer.nioBuffer();
2571 if (!nioBuffer.isDirect()) {
2572 throw new RuntimeException("Allocator returned non-direct buffer");
2573 }
2574
2575 finishCurrentBuffer();
2576 buffers.addFirst(allocatedBuffer);
2577
2578 buffer = nioBuffer;
2579 buffer.limit(buffer.capacity());
2580 buffer.position(0);
2581
2582 bufferOffset = UnsafeUtil.addressOffset(buffer);
2583 limitMinusOne = bufferOffset + (buffer.limit() - 1);
2584 pos = limitMinusOne;
2585 }
2586
2587 @Override
2588 public int getTotalBytesWritten() {
2589 return totalDoneBytes + bytesWrittenToCurrentBuffer();
2590 }
2591
2592 private int bytesWrittenToCurrentBuffer() {
2593 return (int) (limitMinusOne - pos);
2594 }
2595
2596 private int spaceLeft() {
2597 return bufferPos() + 1;
2598 }
2599
2600 @Override
2601 void finishCurrentBuffer() {
2602 if (buffer != null) {
2603 totalDoneBytes += bytesWrittenToCurrentBuffer();
2604 // Update the indices on the netty buffer.
2605 buffer.position(bufferPos() + 1);
2606 buffer = null;
2607 pos = 0;
2608 limitMinusOne = 0;
2609 }
2610 }
2611
2612 private int bufferPos() {
2613 return (int) (pos - bufferOffset);
2614 }
2615
2616 @Override
2617 public void writeUInt32(int fieldNumber, int value) {
2618 requireSpace(MAX_VARINT32_SIZE * 2);
2619 writeVarint32(value);
2620 writeTag(fieldNumber, WIRETYPE_VARINT);
2621 }
2622
2623 @Override
2624 public void writeInt32(int fieldNumber, int value) {
2625 requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
2626 writeInt32(value);
2627 writeTag(fieldNumber, WIRETYPE_VARINT);
2628 }
2629
2630 @Override
2631 public void writeSInt32(int fieldNumber, int value) {
2632 requireSpace(MAX_VARINT32_SIZE * 2);
2633 writeSInt32(value);
2634 writeTag(fieldNumber, WIRETYPE_VARINT);
2635 }
2636
2637 @Override
2638 public void writeFixed32(int fieldNumber, int value) {
2639 requireSpace(MAX_VARINT32_SIZE + FIXED32_SIZE);
2640 writeFixed32(value);
2641 writeTag(fieldNumber, WIRETYPE_FIXED32);
2642 }
2643
2644 @Override
2645 public void writeUInt64(int fieldNumber, long value) {
2646 requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
2647 writeVarint64(value);
2648 writeTag(fieldNumber, WIRETYPE_VARINT);
2649 }
2650
2651 @Override
2652 public void writeSInt64(int fieldNumber, long value) {
2653 requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
2654 writeSInt64(value);
2655 writeTag(fieldNumber, WIRETYPE_VARINT);
2656 }
2657
2658 @Override
2659 public void writeFixed64(int fieldNumber, long value) {
2660 requireSpace(MAX_VARINT32_SIZE + FIXED64_SIZE);
2661 writeFixed64(value);
2662 writeTag(fieldNumber, WIRETYPE_FIXED64);
2663 }
2664
2665 @Override
2666 public void writeBool(int fieldNumber, boolean value) {
2667 requireSpace(MAX_VARINT32_SIZE + 1);
2668 write((byte) (value ? 1 : 0));
2669 writeTag(fieldNumber, WIRETYPE_VARINT);
2670 }
2671
2672 @Override
2673 public void writeString(int fieldNumber, String value) {
2674 int prevBytes = getTotalBytesWritten();
2675 writeString(value);
2676 int length = getTotalBytesWritten() - prevBytes;
2677 requireSpace(2 * MAX_VARINT32_SIZE);
2678 writeVarint32(length);
2679 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
2680 }
2681
2682 @Override
2683 public void writeBytes(int fieldNumber, ByteString value) {
2684 try {
2685 value.writeToReverse(this);
2686 } catch (IOException e) {
2687 // Should never happen since the writer does not throw.
2688 throw new RuntimeException(e);
2689 }
2690
2691 requireSpace(MAX_VARINT32_SIZE * 2);
2692 writeVarint32(value.size());
2693 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
2694 }
2695
2696 @Override
2697 public void writeMessage(int fieldNumber, Object value) throws IOException {
2698 int prevBytes = getTotalBytesWritten();
2699 Protobuf.getInstance().writeTo(value, this);
2700 int length = getTotalBytesWritten() - prevBytes;
2701 requireSpace(MAX_VARINT32_SIZE * 2);
2702 writeVarint32(length);
2703 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
2704 }
2705
2706 @Override
2707 public void writeMessage(int fieldNumber, Object value, Schema schema) throws IOException {
2708 int prevBytes = getTotalBytesWritten();
2709 schema.writeTo(value, this);
2710 int length = getTotalBytesWritten() - prevBytes;
2711 requireSpace(MAX_VARINT32_SIZE * 2);
2712 writeVarint32(length);
2713 writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
2714 }
2715
2716 @Override
2717 public void writeGroup(int fieldNumber, Object value) throws IOException {
2718 writeTag(fieldNumber, WIRETYPE_END_GROUP);
2719 Protobuf.getInstance().writeTo(value, this);
2720 writeTag(fieldNumber, WIRETYPE_START_GROUP);
2721 }
2722
2723 @Override
2724 public void writeGroup(int fieldNumber, Object value, Schema schema) throws IOException {
2725 writeTag(fieldNumber, WIRETYPE_END_GROUP);
2726 schema.writeTo(value, this);
2727 writeTag(fieldNumber, WIRETYPE_START_GROUP);
2728 }
2729
2730 @Deprecated
2731 @Override
2732 public void writeStartGroup(int fieldNumber) {
2733 writeTag(fieldNumber, WIRETYPE_START_GROUP);
2734 }
2735
2736 @Deprecated
2737 @Override
2738 public void writeEndGroup(int fieldNumber) {
2739 writeTag(fieldNumber, WIRETYPE_END_GROUP);
2740 }
2741
2742 @Override
2743 void writeInt32(int value) {
2744 if (value >= 0) {
2745 writeVarint32(value);
2746 } else {
2747 writeVarint64(value);
2748 }
2749 }
2750
2751 @Override
2752 void writeSInt32(int value) {
2753 writeVarint32(CodedOutputStream.encodeZigZag32(value));
2754 }
2755
2756 @Override
2757 void writeSInt64(long value) {
2758 writeVarint64(CodedOutputStream.encodeZigZag64(value));
2759 }
2760
2761 @Override
2762 void writeBool(boolean value) {
2763 write((byte) (value ? 1 : 0));
2764 }
2765
2766 @Override
2767 void writeTag(int fieldNumber, int wireType) {
2768 writeVarint32(WireFormat.makeTag(fieldNumber, wireType));
2769 }
2770
2771 @Override
2772 void writeVarint32(int value) {
2773 if ((value & (~0 << 7)) == 0) {
2774 writeVarint32OneByte(value);
2775 } else if ((value & (~0 << 14)) == 0) {
2776 writeVarint32TwoBytes(value);
2777 } else if ((value & (~0 << 21)) == 0) {
2778 writeVarint32ThreeBytes(value);
2779 } else if ((value & (~0 << 28)) == 0) {
2780 writeVarint32FourBytes(value);
2781 } else {
2782 writeVarint32FiveBytes(value);
2783 }
2784 }
2785
2786 private void writeVarint32OneByte(int value) {
2787 UnsafeUtil.putByte(pos--, (byte) value);
2788 }
2789
2790 private void writeVarint32TwoBytes(int value) {
2791 UnsafeUtil.putByte(pos--, (byte) (value >>> 7));
2792 UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
2793 }
2794
2795 private void writeVarint32ThreeBytes(int value) {
2796 UnsafeUtil.putByte(pos--, (byte) (value >>> 14));
2797 UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
2798 UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
2799 }
2800
2801 private void writeVarint32FourBytes(int value) {
2802 UnsafeUtil.putByte(pos--, (byte) (value >>> 21));
2803 UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
2804 UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
2805 UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
2806 }
2807
2808 private void writeVarint32FiveBytes(int value) {
2809 UnsafeUtil.putByte(pos--, (byte) (value >>> 28));
2810 UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
2811 UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
2812 UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
2813 UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
2814 }
2815
2816 @Override
2817 void writeVarint64(long value) {
2818 switch (computeUInt64SizeNoTag(value)) {
2819 case 1:
2820 writeVarint64OneByte(value);
2821 break;
2822 case 2:
2823 writeVarint64TwoBytes(value);
2824 break;
2825 case 3:
2826 writeVarint64ThreeBytes(value);
2827 break;
2828 case 4:
2829 writeVarint64FourBytes(value);
2830 break;
2831 case 5:
2832 writeVarint64FiveBytes(value);
2833 break;
2834 case 6:
2835 writeVarint64SixBytes(value);
2836 break;
2837 case 7:
2838 writeVarint64SevenBytes(value);
2839 break;
2840 case 8:
2841 writeVarint64EightBytes(value);
2842 break;
2843 case 9:
2844 writeVarint64NineBytes(value);
2845 break;
2846 case 10:
2847 writeVarint64TenBytes(value);
2848 break;
2849 }
2850 }
2851
2852 private void writeVarint64OneByte(long value) {
2853 UnsafeUtil.putByte(pos--, (byte) value);
2854 }
2855
2856 private void writeVarint64TwoBytes(long value) {
2857 UnsafeUtil.putByte(pos--, (byte) (value >>> 7));
2858 UnsafeUtil.putByte(pos--, (byte) (((int) value & 0x7F) | 0x80));
2859 }
2860
2861 private void writeVarint64ThreeBytes(long value) {
2862 UnsafeUtil.putByte(pos--, (byte) (((int) value) >>> 14));
2863 UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
2864 UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
2865 }
2866
2867 private void writeVarint64FourBytes(long value) {
2868 UnsafeUtil.putByte(pos--, (byte) (value >>> 21));
2869 UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
2870 UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
2871 UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
2872 }
2873
2874 private void writeVarint64FiveBytes(long value) {
2875 UnsafeUtil.putByte(pos--, (byte) (value >>> 28));
2876 UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
2877 UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
2878 UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
2879 UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
2880 }
2881
2882 private void writeVarint64SixBytes(long value) {
2883 UnsafeUtil.putByte(pos--, (byte) (value >>> 35));
2884 UnsafeUtil.putByte(pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
2885 UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
2886 UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
2887 UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
2888 UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
2889 }
2890
2891 private void writeVarint64SevenBytes(long value) {
2892 UnsafeUtil.putByte(pos--, (byte) (value >>> 42));
2893 UnsafeUtil.putByte(pos--, (byte) (((value >>> 35) & 0x7F) | 0x80));
2894 UnsafeUtil.putByte(pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
2895 UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
2896 UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
2897 UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
2898 UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
2899 }
2900
2901 private void writeVarint64EightBytes(long value) {
2902 UnsafeUtil.putByte(pos--, (byte) (value >>> 49));
2903 UnsafeUtil.putByte(pos--, (byte) (((value >>> 42) & 0x7F) | 0x80));
2904 UnsafeUtil.putByte(pos--, (byte) (((value >>> 35) & 0x7F) | 0x80));
2905 UnsafeUtil.putByte(pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
2906 UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
2907 UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
2908 UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
2909 UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
2910 }
2911
2912 private void writeVarint64NineBytes(long value) {
2913 UnsafeUtil.putByte(pos--, (byte) (value >>> 56));
2914 UnsafeUtil.putByte(pos--, (byte) (((value >>> 49) & 0x7F) | 0x80));
2915 UnsafeUtil.putByte(pos--, (byte) (((value >>> 42) & 0x7F) | 0x80));
2916 UnsafeUtil.putByte(pos--, (byte) (((value >>> 35) & 0x7F) | 0x80));
2917 UnsafeUtil.putByte(pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
2918 UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
2919 UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
2920 UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
2921 UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
2922 }
2923
2924 private void writeVarint64TenBytes(long value) {
2925 UnsafeUtil.putByte(pos--, (byte) (value >>> 63));
2926 UnsafeUtil.putByte(pos--, (byte) (((value >>> 56) & 0x7F) | 0x80));
2927 UnsafeUtil.putByte(pos--, (byte) (((value >>> 49) & 0x7F) | 0x80));
2928 UnsafeUtil.putByte(pos--, (byte) (((value >>> 42) & 0x7F) | 0x80));
2929 UnsafeUtil.putByte(pos--, (byte) (((value >>> 35) & 0x7F) | 0x80));
2930 UnsafeUtil.putByte(pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
2931 UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
2932 UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
2933 UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
2934 UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
2935 }
2936
2937 @Override
2938 void writeFixed32(int value) {
2939 UnsafeUtil.putByte(pos--, (byte) ((value >> 24) & 0xFF));
2940 UnsafeUtil.putByte(pos--, (byte) ((value >> 16) & 0xFF));
2941 UnsafeUtil.putByte(pos--, (byte) ((value >> 8) & 0xFF));
2942 UnsafeUtil.putByte(pos--, (byte) (value & 0xFF));
2943 }
2944
2945 @Override
2946 void writeFixed64(long value) {
2947 UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 56) & 0xFF));
2948 UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 48) & 0xFF));
2949 UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 40) & 0xFF));
2950 UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 32) & 0xFF));
2951 UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 24) & 0xFF));
2952 UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 16) & 0xFF));
2953 UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 8) & 0xFF));
2954 UnsafeUtil.putByte(pos--, (byte) ((int) (value) & 0xFF));
2955 }
2956
2957 @Override
2958 void writeString(String in) {
2959 // Request enough space to write the ASCII string.
2960 requireSpace(in.length());
2961
2962 // We know the buffer is big enough...
2963 int i = in.length() - 1;
2964 // Designed to take advantage of
2965 // https://wiki.openjdk.java.net/display/HotSpotInternals/RangeCheckElimination
2966 for (char c; i >= 0 && (c = in.charAt(i)) < 0x80; i--) {
2967 UnsafeUtil.putByte(pos--, (byte) c);
2968 }
2969 if (i == -1) {
2970 // ASCII.
2971 return;
2972 }
2973 for (char c; i >= 0; i--) {
2974 c = in.charAt(i);
2975 if (c < 0x80 && pos >= bufferOffset) {
2976 UnsafeUtil.putByte(pos--, (byte) c);
2977 } else if (c < 0x800 && pos > bufferOffset) { // 11 bits, two UTF-8 bytes
2978 UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & c)));
2979 UnsafeUtil.putByte(pos--, (byte) ((0xF << 6) | (c >>> 6)));
2980 } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c)
2981 && pos > bufferOffset + 1) {
2982 // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
2983 UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & c)));
2984 UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & (c >>> 6))));
2985 UnsafeUtil.putByte(pos--, (byte) ((0xF << 5) | (c >>> 12)));
2986 } else if (pos > bufferOffset + 2) {
2987 // Minimum code point represented by a surrogate pair is 0x10000, 17 bits,
2988 // four UTF-8 bytes
2989 final char high;
2990 if (i == 0 || !Character.isSurrogatePair(high = in.charAt(i - 1), c)) {
2991 throw new Utf8.UnpairedSurrogateException(i - 1, i);
2992 }
2993 i--;
2994 int codePoint = Character.toCodePoint(high, c);
2995 UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & codePoint)));
2996 UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
2997 UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
2998 UnsafeUtil.putByte(pos--, (byte) ((0xF << 4) | (codePoint >>> 18)));
2999 } else {
3000 // Buffer is full - allocate a new one and revisit the current character.
3001 requireSpace(i);
3002 i++;
3003 }
3004 }
3005 }
3006
3007 @Override
3008 public void write(byte value) {
3009 UnsafeUtil.putByte(pos--, value);
3010 }
3011
3012 @Override
3013 public void write(byte[] value, int offset, int length) {
3014 if (spaceLeft() < length) {
3015 nextBuffer(length);
3016 }
3017
3018 pos -= length;
3019 buffer.position(bufferPos() + 1);
3020 buffer.put(value, offset, length);
3021 }
3022
3023 @Override
3024 public void writeLazy(byte[] value, int offset, int length) {
3025 if (spaceLeft() < length) {
3026 // We consider the value to be immutable (likely the internals of a ByteString). Just
3027 // wrap it in a Netty buffer and add it to the output buffer.
3028 totalDoneBytes += length;
3029 buffers.addFirst(AllocatedBuffer.wrap(value, offset, length));
3030
3031 // Advance the writer to the next buffer.
3032 // TODO(nathanmittler): Consider slicing if space available above some threshold.
3033 nextBuffer();
3034 return;
3035 }
3036
3037 pos -= length;
3038 buffer.position(bufferPos() + 1);
3039 buffer.put(value, offset, length);
3040 }
3041
3042 @Override
3043 public void write(ByteBuffer value) {
3044 int length = value.remaining();
3045 if (spaceLeft() < length) {
3046 nextBuffer(length);
3047 }
3048
3049 pos -= length;
3050 buffer.position(bufferPos() + 1);
3051 buffer.put(value);
3052 }
3053
3054 @Override
3055 public void writeLazy(ByteBuffer value) {
3056 int length = value.remaining();
3057 if (spaceLeft() < length) {
3058 // We consider the value to be immutable (likely the internals of a ByteString). Just
3059 // wrap it in a Netty buffer and add it to the output buffer.
3060 totalDoneBytes += length;
3061 buffers.addFirst(AllocatedBuffer.wrap(value));
3062
3063 // Advance the writer to the next buffer.
3064 // TODO(nathanmittler): Consider slicing if space available above some threshold.
3065 nextBuffer();
3066 return;
3067 }
3068
3069 pos -= length;
3070 buffer.position(bufferPos() + 1);
3071 buffer.put(value);
3072 }
3073
3074 @Override
3075 void requireSpace(int size) {
3076 if (spaceLeft() < size) {
3077 nextBuffer(size);
3078 }
3079 }
3080 }
3081}