1 // 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 31 package com.google.protobuf; 32 33 import java.io.IOException; 34 import java.lang.reflect.Method; 35 import java.nio.ByteBuffer; 36 import java.nio.charset.Charset; 37 import java.util.AbstractList; 38 import java.util.AbstractMap; 39 import java.util.AbstractSet; 40 import java.util.Arrays; 41 import java.util.Iterator; 42 import java.util.List; 43 import java.util.Map; 44 import java.util.RandomAccess; 45 import java.util.Set; 46 47 /** 48 * The classes contained within are used internally by the Protocol Buffer 49 * library and generated message implementations. They are public only because 50 * those generated messages do not reside in the {@code protobuf} package. 51 * Others should not use this class directly. 52 * 53 * @author kenton@google.com (Kenton Varda) 54 */ 55 public final class Internal { 56 Internal()57 private Internal() {} 58 59 static final Charset UTF_8 = Charset.forName("UTF-8"); 60 static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); 61 62 /** 63 * Helper called by generated code to construct default values for string 64 * fields. 65 * <p> 66 * The protocol compiler does not actually contain a UTF-8 decoder -- it 67 * just pushes UTF-8-encoded text around without touching it. The one place 68 * where this presents a problem is when generating Java string literals. 69 * Unicode characters in the string literal would normally need to be encoded 70 * using a Unicode escape sequence, which would require decoding them. 71 * To get around this, protoc instead embeds the UTF-8 bytes into the 72 * generated code and leaves it to the runtime library to decode them. 73 * <p> 74 * It gets worse, though. If protoc just generated a byte array, like: 75 * new byte[] {0x12, 0x34, 0x56, 0x78} 76 * Java actually generates *code* which allocates an array and then fills 77 * in each value. This is much less efficient than just embedding the bytes 78 * directly into the bytecode. To get around this, we need another 79 * work-around. String literals are embedded directly, so protoc actually 80 * generates a string literal corresponding to the bytes. The easiest way 81 * to do this is to use the ISO-8859-1 character set, which corresponds to 82 * the first 256 characters of the Unicode range. Protoc can then use 83 * good old CEscape to generate the string. 84 * <p> 85 * So we have a string literal which represents a set of bytes which 86 * represents another string. This function -- stringDefaultValue -- 87 * converts from the generated string to the string we actually want. The 88 * generated code calls this automatically. 89 */ stringDefaultValue(String bytes)90 public static String stringDefaultValue(String bytes) { 91 return new String(bytes.getBytes(ISO_8859_1), UTF_8); 92 } 93 94 /** 95 * Helper called by generated code to construct default values for bytes 96 * fields. 97 * <p> 98 * This is a lot like {@link #stringDefaultValue}, but for bytes fields. 99 * In this case we only need the second of the two hacks -- allowing us to 100 * embed raw bytes as a string literal with ISO-8859-1 encoding. 101 */ bytesDefaultValue(String bytes)102 public static ByteString bytesDefaultValue(String bytes) { 103 return ByteString.copyFrom(bytes.getBytes(ISO_8859_1)); 104 } 105 /** 106 * Helper called by generated code to construct default values for bytes 107 * fields. 108 * <p> 109 * This is like {@link #bytesDefaultValue}, but returns a byte array. 110 */ byteArrayDefaultValue(String bytes)111 public static byte[] byteArrayDefaultValue(String bytes) { 112 return bytes.getBytes(ISO_8859_1); 113 } 114 115 /** 116 * Helper called by generated code to construct default values for bytes 117 * fields. 118 * <p> 119 * This is like {@link #bytesDefaultValue}, but returns a ByteBuffer. 120 */ byteBufferDefaultValue(String bytes)121 public static ByteBuffer byteBufferDefaultValue(String bytes) { 122 return ByteBuffer.wrap(byteArrayDefaultValue(bytes)); 123 } 124 125 /** 126 * Create a new ByteBuffer and copy all the content of {@code source} 127 * ByteBuffer to the new ByteBuffer. The new ByteBuffer's limit and 128 * capacity will be source.capacity(), and its position will be 0. 129 * Note that the state of {@code source} ByteBuffer won't be changed. 130 */ copyByteBuffer(ByteBuffer source)131 public static ByteBuffer copyByteBuffer(ByteBuffer source) { 132 // Make a duplicate of the source ByteBuffer and read data from the 133 // duplicate. This is to avoid affecting the source ByteBuffer's state. 134 ByteBuffer temp = source.duplicate(); 135 // We want to copy all the data in the source ByteBuffer, not just the 136 // remaining bytes. 137 temp.clear(); 138 ByteBuffer result = ByteBuffer.allocate(temp.capacity()); 139 result.put(temp); 140 result.clear(); 141 return result; 142 } 143 144 /** 145 * Helper called by generated code to determine if a byte array is a valid 146 * UTF-8 encoded string such that the original bytes can be converted to 147 * a String object and then back to a byte array round tripping the bytes 148 * without loss. More precisely, returns {@code true} whenever: 149 * <pre> {@code 150 * Arrays.equals(byteString.toByteArray(), 151 * new String(byteString.toByteArray(), "UTF-8").getBytes("UTF-8")) 152 * }</pre> 153 * 154 * <p>This method rejects "overlong" byte sequences, as well as 155 * 3-byte sequences that would map to a surrogate character, in 156 * accordance with the restricted definition of UTF-8 introduced in 157 * Unicode 3.1. Note that the UTF-8 decoder included in Oracle's 158 * JDK has been modified to also reject "overlong" byte sequences, 159 * but currently (2011) still accepts 3-byte surrogate character 160 * byte sequences. 161 * 162 * <p>See the Unicode Standard,<br> 163 * Table 3-6. <em>UTF-8 Bit Distribution</em>,<br> 164 * Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>. 165 * 166 * <p>As of 2011-02, this method simply returns the result of {@link 167 * ByteString#isValidUtf8()}. Calling that method directly is preferred. 168 * 169 * @param byteString the string to check 170 * @return whether the byte array is round trippable 171 */ isValidUtf8(ByteString byteString)172 public static boolean isValidUtf8(ByteString byteString) { 173 return byteString.isValidUtf8(); 174 } 175 176 /** 177 * Like {@link #isValidUtf8(ByteString)} but for byte arrays. 178 */ isValidUtf8(byte[] byteArray)179 public static boolean isValidUtf8(byte[] byteArray) { 180 return Utf8.isValidUtf8(byteArray); 181 } 182 183 /** 184 * Helper method to get the UTF-8 bytes of a string. 185 */ toByteArray(String value)186 public static byte[] toByteArray(String value) { 187 return value.getBytes(UTF_8); 188 } 189 190 /** 191 * Helper method to convert a byte array to a string using UTF-8 encoding. 192 */ toStringUtf8(byte[] bytes)193 public static String toStringUtf8(byte[] bytes) { 194 return new String(bytes, UTF_8); 195 } 196 197 /** 198 * Interface for an enum value or value descriptor, to be used in FieldSet. 199 * The lite library stores enum values directly in FieldSets but the full 200 * library stores EnumValueDescriptors in order to better support reflection. 201 */ 202 public interface EnumLite { getNumber()203 int getNumber(); 204 } 205 206 /** 207 * Interface for an object which maps integers to {@link EnumLite}s. 208 * {@link Descriptors.EnumDescriptor} implements this interface by mapping 209 * numbers to {@link Descriptors.EnumValueDescriptor}s. Additionally, 210 * every generated enum type has a static method internalGetValueMap() which 211 * returns an implementation of this type that maps numbers to enum values. 212 */ 213 public interface EnumLiteMap<T extends EnumLite> { findValueByNumber(int number)214 T findValueByNumber(int number); 215 } 216 217 /** 218 * Helper method for implementing {@link Message#hashCode()} for longs. 219 * @see Long#hashCode() 220 */ hashLong(long n)221 public static int hashLong(long n) { 222 return (int) (n ^ (n >>> 32)); 223 } 224 225 /** 226 * Helper method for implementing {@link Message#hashCode()} for 227 * booleans. 228 * @see Boolean#hashCode() 229 */ hashBoolean(boolean b)230 public static int hashBoolean(boolean b) { 231 return b ? 1231 : 1237; 232 } 233 234 /** 235 * Helper method for implementing {@link Message#hashCode()} for enums. 236 * <p> 237 * This is needed because {@link java.lang.Enum#hashCode()} is final, but we 238 * need to use the field number as the hash code to ensure compatibility 239 * between statically and dynamically generated enum objects. 240 */ hashEnum(EnumLite e)241 public static int hashEnum(EnumLite e) { 242 return e.getNumber(); 243 } 244 245 /** 246 * Helper method for implementing {@link Message#hashCode()} for 247 * enum lists. 248 */ hashEnumList(List<? extends EnumLite> list)249 public static int hashEnumList(List<? extends EnumLite> list) { 250 int hash = 1; 251 for (EnumLite e : list) { 252 hash = 31 * hash + hashEnum(e); 253 } 254 return hash; 255 } 256 257 /** 258 * Helper method for implementing {@link Message#equals(Object)} for bytes field. 259 */ equals(List<byte[]> a, List<byte[]> b)260 public static boolean equals(List<byte[]> a, List<byte[]> b) { 261 if (a.size() != b.size()) return false; 262 for (int i = 0; i < a.size(); ++i) { 263 if (!Arrays.equals(a.get(i), b.get(i))) { 264 return false; 265 } 266 } 267 return true; 268 } 269 270 /** 271 * Helper method for implementing {@link Message#hashCode()} for bytes field. 272 */ hashCode(List<byte[]> list)273 public static int hashCode(List<byte[]> list) { 274 int hash = 1; 275 for (byte[] bytes : list) { 276 hash = 31 * hash + hashCode(bytes); 277 } 278 return hash; 279 } 280 281 /** 282 * Helper method for implementing {@link Message#hashCode()} for bytes field. 283 */ hashCode(byte[] bytes)284 public static int hashCode(byte[] bytes) { 285 // The hash code for a byte array should be the same as the hash code for a 286 // ByteString with the same content. This is to ensure that the generated 287 // hashCode() method will return the same value as the pure reflection 288 // based hashCode() method. 289 return Internal.hashCode(bytes, 0, bytes.length); 290 } 291 292 /** 293 * Helper method for implementing {@link LiteralByteString#hashCode()}. 294 */ hashCode(byte[] bytes, int offset, int length)295 static int hashCode(byte[] bytes, int offset, int length) { 296 // The hash code for a byte array should be the same as the hash code for a 297 // ByteString with the same content. This is to ensure that the generated 298 // hashCode() method will return the same value as the pure reflection 299 // based hashCode() method. 300 int h = Internal.partialHash(length, bytes, offset, length); 301 return h == 0 ? 1 : h; 302 } 303 304 /** 305 * Helper method for continuously hashing bytes. 306 */ partialHash(int h, byte[] bytes, int offset, int length)307 static int partialHash(int h, byte[] bytes, int offset, int length) { 308 for (int i = offset; i < offset + length; i++) { 309 h = h * 31 + bytes[i]; 310 } 311 return h; 312 } 313 314 /** 315 * Helper method for implementing {@link Message#equals(Object)} for bytes 316 * field. 317 */ equalsByteBuffer(ByteBuffer a, ByteBuffer b)318 public static boolean equalsByteBuffer(ByteBuffer a, ByteBuffer b) { 319 if (a.capacity() != b.capacity()) { 320 return false; 321 } 322 // ByteBuffer.equals() will only compare the remaining bytes, but we want to 323 // compare all the content. 324 return a.duplicate().clear().equals(b.duplicate().clear()); 325 } 326 327 /** 328 * Helper method for implementing {@link Message#equals(Object)} for bytes 329 * field. 330 */ equalsByteBuffer( List<ByteBuffer> a, List<ByteBuffer> b)331 public static boolean equalsByteBuffer( 332 List<ByteBuffer> a, List<ByteBuffer> b) { 333 if (a.size() != b.size()) { 334 return false; 335 } 336 for (int i = 0; i < a.size(); ++i) { 337 if (!equalsByteBuffer(a.get(i), b.get(i))) { 338 return false; 339 } 340 } 341 return true; 342 } 343 344 /** 345 * Helper method for implementing {@link Message#hashCode()} for bytes 346 * field. 347 */ hashCodeByteBuffer(List<ByteBuffer> list)348 public static int hashCodeByteBuffer(List<ByteBuffer> list) { 349 int hash = 1; 350 for (ByteBuffer bytes : list) { 351 hash = 31 * hash + hashCodeByteBuffer(bytes); 352 } 353 return hash; 354 } 355 356 private static final int DEFAULT_BUFFER_SIZE = 4096; 357 358 /** 359 * Helper method for implementing {@link Message#hashCode()} for bytes 360 * field. 361 */ hashCodeByteBuffer(ByteBuffer bytes)362 public static int hashCodeByteBuffer(ByteBuffer bytes) { 363 if (bytes.hasArray()) { 364 // Fast path. 365 int h = partialHash(bytes.capacity(), bytes.array(), bytes.arrayOffset(), bytes.capacity()); 366 return h == 0 ? 1 : h; 367 } else { 368 // Read the data into a temporary byte array before calculating the 369 // hash value. 370 final int bufferSize = bytes.capacity() > DEFAULT_BUFFER_SIZE 371 ? DEFAULT_BUFFER_SIZE : bytes.capacity(); 372 final byte[] buffer = new byte[bufferSize]; 373 final ByteBuffer duplicated = bytes.duplicate(); 374 duplicated.clear(); 375 int h = bytes.capacity(); 376 while (duplicated.remaining() > 0) { 377 final int length = duplicated.remaining() <= bufferSize ? 378 duplicated.remaining() : bufferSize; 379 duplicated.get(buffer, 0, length); 380 h = partialHash(h, buffer, 0, length); 381 } 382 return h == 0 ? 1 : h; 383 } 384 } 385 386 @SuppressWarnings("unchecked") getDefaultInstance(Class<T> clazz)387 public static <T extends MessageLite> T getDefaultInstance(Class<T> clazz) { 388 try { 389 Method method = clazz.getMethod("getDefaultInstance"); 390 return (T) method.invoke(method); 391 } catch (Exception e) { 392 throw new RuntimeException( 393 "Failed to get default instance for " + clazz, e); 394 } 395 } 396 397 /** 398 * An empty byte array constant used in generated code. 399 */ 400 public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; 401 402 /** 403 * An empty byte array constant used in generated code. 404 */ 405 public static final ByteBuffer EMPTY_BYTE_BUFFER = 406 ByteBuffer.wrap(EMPTY_BYTE_ARRAY); 407 408 /** An empty coded input stream constant used in generated code. */ 409 public static final CodedInputStream EMPTY_CODED_INPUT_STREAM = 410 CodedInputStream.newInstance(EMPTY_BYTE_ARRAY); 411 412 413 /** 414 * Provides an immutable view of {@code List<T>} around a {@code List<F>}. 415 * 416 * Protobuf internal. Used in protobuf generated code only. 417 */ 418 public static class ListAdapter<F, T> extends AbstractList<T> { 419 /** 420 * Convert individual elements of the List from F to T. 421 */ 422 public interface Converter<F, T> { convert(F from)423 T convert(F from); 424 } 425 426 private final List<F> fromList; 427 private final Converter<F, T> converter; 428 ListAdapter(List<F> fromList, Converter<F, T> converter)429 public ListAdapter(List<F> fromList, Converter<F, T> converter) { 430 this.fromList = fromList; 431 this.converter = converter; 432 } 433 434 @Override get(int index)435 public T get(int index) { 436 return converter.convert(fromList.get(index)); 437 } 438 439 @Override size()440 public int size() { 441 return fromList.size(); 442 } 443 } 444 445 /** 446 * Wrap around a {@code Map<K, RealValue>} and provide a {@code Map<K, V>} 447 * interface. 448 */ 449 public static class MapAdapter<K, V, RealValue> extends AbstractMap<K, V> { 450 /** 451 * An interface used to convert between two types. 452 */ 453 public interface Converter<A, B> { doForward(A object)454 B doForward(A object); doBackward(B object)455 A doBackward(B object); 456 } 457 newEnumConverter( final EnumLiteMap<T> enumMap, final T unrecognizedValue)458 public static <T extends EnumLite> Converter<Integer, T> newEnumConverter( 459 final EnumLiteMap<T> enumMap, final T unrecognizedValue) { 460 return new Converter<Integer, T>() { 461 @Override 462 public T doForward(Integer value) { 463 T result = enumMap.findValueByNumber(value); 464 return result == null ? unrecognizedValue : result; 465 } 466 467 @Override 468 public Integer doBackward(T value) { 469 return value.getNumber(); 470 } 471 }; 472 } 473 474 private final Map<K, RealValue> realMap; 475 private final Converter<RealValue, V> valueConverter; 476 MapAdapter(Map<K, RealValue> realMap, Converter<RealValue, V> valueConverter)477 public MapAdapter(Map<K, RealValue> realMap, 478 Converter<RealValue, V> valueConverter) { 479 this.realMap = realMap; 480 this.valueConverter = valueConverter; 481 } 482 483 @SuppressWarnings("unchecked") 484 @Override get(Object key)485 public V get(Object key) { 486 RealValue result = realMap.get(key); 487 if (result == null) { 488 return null; 489 } 490 return valueConverter.doForward(result); 491 } 492 493 @Override put(K key, V value)494 public V put(K key, V value) { 495 RealValue oldValue = realMap.put(key, valueConverter.doBackward(value)); 496 if (oldValue == null) { 497 return null; 498 } 499 return valueConverter.doForward(oldValue); 500 } 501 502 @Override entrySet()503 public Set<java.util.Map.Entry<K, V>> entrySet() { 504 return new SetAdapter(realMap.entrySet()); 505 } 506 507 private class SetAdapter extends AbstractSet<Map.Entry<K, V>> { 508 private final Set<Map.Entry<K, RealValue>> realSet; SetAdapter(Set<Map.Entry<K, RealValue>> realSet)509 public SetAdapter(Set<Map.Entry<K, RealValue>> realSet) { 510 this.realSet = realSet; 511 } 512 513 @Override iterator()514 public Iterator<java.util.Map.Entry<K, V>> iterator() { 515 return new IteratorAdapter(realSet.iterator()); 516 } 517 518 @Override size()519 public int size() { 520 return realSet.size(); 521 } 522 } 523 524 private class IteratorAdapter implements Iterator<Map.Entry<K, V>> { 525 private final Iterator<Map.Entry<K, RealValue>> realIterator; 526 IteratorAdapter( Iterator<Map.Entry<K, RealValue>> realIterator)527 public IteratorAdapter( 528 Iterator<Map.Entry<K, RealValue>> realIterator) { 529 this.realIterator = realIterator; 530 } 531 532 @Override hasNext()533 public boolean hasNext() { 534 return realIterator.hasNext(); 535 } 536 537 @Override next()538 public java.util.Map.Entry<K, V> next() { 539 return new EntryAdapter(realIterator.next()); 540 } 541 542 @Override remove()543 public void remove() { 544 realIterator.remove(); 545 } 546 } 547 548 private class EntryAdapter implements Map.Entry<K, V> { 549 private final Map.Entry<K, RealValue> realEntry; 550 EntryAdapter(Map.Entry<K, RealValue> realEntry)551 public EntryAdapter(Map.Entry<K, RealValue> realEntry) { 552 this.realEntry = realEntry; 553 } 554 555 @Override getKey()556 public K getKey() { 557 return realEntry.getKey(); 558 } 559 560 @Override getValue()561 public V getValue() { 562 return valueConverter.doForward(realEntry.getValue()); 563 } 564 565 @Override setValue(V value)566 public V setValue(V value) { 567 RealValue oldValue = realEntry.setValue( 568 valueConverter.doBackward(value)); 569 if (oldValue == null) { 570 return null; 571 } 572 return valueConverter.doForward(oldValue); 573 } 574 } 575 } 576 577 /** 578 * Extends {@link List} to add the capability to make the list immutable and inspect if it is 579 * modifiable. 580 * <p> 581 * All implementations must support efficient random access. 582 */ 583 public static interface ProtobufList<E> extends List<E>, RandomAccess { 584 585 /** 586 * Makes this list immutable. All subsequent modifications will throw an 587 * {@link UnsupportedOperationException}. 588 */ 589 void makeImmutable(); 590 591 /** 592 * Returns whether this list can be modified via the publicly accessible {@link List} methods. 593 */ 594 boolean isModifiable(); 595 596 /** 597 * Returns a mutable clone of this list with the specified capacity. 598 */ 599 ProtobufList<E> mutableCopyWithCapacity(int capacity); 600 } 601 602 /** 603 * A {@link java.util.List} implementation that avoids boxing the elements into Integers if 604 * possible. Does not support null elements. 605 */ 606 public static interface IntList extends ProtobufList<Integer> { 607 608 /** 609 * Like {@link #get(int)} but more efficient in that it doesn't box the returned value. 610 */ 611 int getInt(int index); 612 613 /** 614 * Like {@link #add(Integer)} but more efficient in that it doesn't box the element. 615 */ 616 void addInt(int element); 617 618 /** 619 * Like {@link #set(int, Integer)} but more efficient in that it doesn't box the element. 620 */ 621 int setInt(int index, int element); 622 623 /** 624 * Returns a mutable clone of this list with the specified capacity. 625 */ 626 @Override 627 IntList mutableCopyWithCapacity(int capacity); 628 } 629 630 /** 631 * A {@link java.util.List} implementation that avoids boxing the elements into Booleans if 632 * possible. Does not support null elements. 633 */ 634 public static interface BooleanList extends ProtobufList<Boolean> { 635 636 /** 637 * Like {@link #get(int)} but more efficient in that it doesn't box the returned value. 638 */ 639 boolean getBoolean(int index); 640 641 /** 642 * Like {@link #add(Boolean)} but more efficient in that it doesn't box the element. 643 */ 644 void addBoolean(boolean element); 645 646 /** 647 * Like {@link #set(int, Boolean)} but more efficient in that it doesn't box the element. 648 */ 649 boolean setBoolean(int index, boolean element); 650 651 /** 652 * Returns a mutable clone of this list with the specified capacity. 653 */ 654 @Override 655 BooleanList mutableCopyWithCapacity(int capacity); 656 } 657 658 /** 659 * A {@link java.util.List} implementation that avoids boxing the elements into Longs if 660 * possible. Does not support null elements. 661 */ 662 public static interface LongList extends ProtobufList<Long> { 663 664 /** 665 * Like {@link #get(int)} but more efficient in that it doesn't box the returned value. 666 */ 667 long getLong(int index); 668 669 /** 670 * Like {@link #add(Long)} but more efficient in that it doesn't box the element. 671 */ 672 void addLong(long element); 673 674 /** 675 * Like {@link #set(int, Long)} but more efficient in that it doesn't box the element. 676 */ 677 long setLong(int index, long element); 678 679 /** 680 * Returns a mutable clone of this list with the specified capacity. 681 */ 682 @Override 683 LongList mutableCopyWithCapacity(int capacity); 684 } 685 686 /** 687 * A {@link java.util.List} implementation that avoids boxing the elements into Doubles if 688 * possible. Does not support null elements. 689 */ 690 public static interface DoubleList extends ProtobufList<Double> { 691 692 /** 693 * Like {@link #get(int)} but more efficient in that it doesn't box the returned value. 694 */ 695 double getDouble(int index); 696 697 /** 698 * Like {@link #add(Double)} but more efficient in that it doesn't box the element. 699 */ 700 void addDouble(double element); 701 702 /** 703 * Like {@link #set(int, Double)} but more efficient in that it doesn't box the element. 704 */ 705 double setDouble(int index, double element); 706 707 /** 708 * Returns a mutable clone of this list with the specified capacity. 709 */ 710 @Override 711 DoubleList mutableCopyWithCapacity(int capacity); 712 } 713 714 /** 715 * A {@link java.util.List} implementation that avoids boxing the elements into Floats if 716 * possible. Does not support null elements. 717 */ 718 public static interface FloatList extends ProtobufList<Float> { 719 720 /** 721 * Like {@link #get(int)} but more efficient in that it doesn't box the returned value. 722 */ 723 float getFloat(int index); 724 725 /** 726 * Like {@link #add(Float)} but more efficient in that it doesn't box the element. 727 */ 728 void addFloat(float element); 729 730 /** 731 * Like {@link #set(int, Float)} but more efficient in that it doesn't box the element. 732 */ 733 float setFloat(int index, float element); 734 735 /** 736 * Returns a mutable clone of this list with the specified capacity. 737 */ 738 @Override 739 FloatList mutableCopyWithCapacity(int capacity); 740 } 741 } 742