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