Home | History | Annotate | Download | only in protobuf
      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 (at) google.com (Kenton Varda)
     54  */
     55 public final class Internal {
     56 
     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    */
     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    */
    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    */
    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    */
    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    */
    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    */
    172   public static boolean isValidUtf8(ByteString byteString) {
    173     return byteString.isValidUtf8();
    174   }
    175 
    176   /**
    177    * Like {@link #isValidUtf8(ByteString)} but for byte arrays.
    178    */
    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    */
    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    */
    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 {
    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> {
    214     T findValueByNumber(int number);
    215   }
    216 
    217   /**
    218    * Helper method for implementing {@link Message#hashCode()} for longs.
    219    * @see Long#hashCode()
    220    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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")
    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> {
    423       T convert(F from);
    424     }
    425 
    426     private final List<F> fromList;
    427     private final Converter<F, T> converter;
    428 
    429     public ListAdapter(List<F> fromList, Converter<F, T> converter) {
    430       this.fromList = fromList;
    431       this.converter = converter;
    432     }
    433 
    434     @Override
    435     public T get(int index) {
    436       return converter.convert(fromList.get(index));
    437     }
    438 
    439     @Override
    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> {
    454       B doForward(A object);
    455       A doBackward(B object);
    456     }
    457 
    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 
    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
    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
    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
    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;
    509       public SetAdapter(Set<Map.Entry<K, RealValue>> realSet) {
    510         this.realSet = realSet;
    511       }
    512 
    513       @Override
    514       public Iterator<java.util.Map.Entry<K, V>> iterator() {
    515         return new IteratorAdapter(realSet.iterator());
    516       }
    517 
    518       @Override
    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 
    527       public IteratorAdapter(
    528           Iterator<Map.Entry<K, RealValue>> realIterator) {
    529         this.realIterator = realIterator;
    530       }
    531 
    532       @Override
    533       public boolean hasNext() {
    534         return realIterator.hasNext();
    535       }
    536 
    537       @Override
    538       public java.util.Map.Entry<K, V> next() {
    539         return new EntryAdapter(realIterator.next());
    540       }
    541 
    542       @Override
    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 
    551       public EntryAdapter(Map.Entry<K, RealValue> realEntry) {
    552         this.realEntry = realEntry;
    553       }
    554 
    555       @Override
    556       public K getKey() {
    557         return realEntry.getKey();
    558       }
    559 
    560       @Override
    561       public V getValue() {
    562         return valueConverter.doForward(realEntry.getValue());
    563       }
    564 
    565       @Override
    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