From 5221dcbe479ed765d8103ed7601c69b6d8d6ca4f Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Fri, 29 Jan 2016 13:51:05 -0800 Subject: Integrate from google internal. Java files are moved to un-do the hack in the prevous commit, which moved the java files to the original position for integration. --- .../main/java/com/google/protobuf/Internal.java | 669 +++++++++++++++++++++ 1 file changed, 669 insertions(+) create mode 100644 java/core/src/main/java/com/google/protobuf/Internal.java (limited to 'java/core/src/main/java/com/google/protobuf/Internal.java') diff --git a/java/core/src/main/java/com/google/protobuf/Internal.java b/java/core/src/main/java/com/google/protobuf/Internal.java new file mode 100644 index 00000000..dca5f23b --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/Internal.java @@ -0,0 +1,669 @@ +// Copyright 2007 Google Inc. All rights reserved. + +package com.google.protobuf; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.AbstractList; +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * The classes contained within are used internally by the Protocol Buffer + * library and generated message implementations. They are public only because + * those generated messages do not reside in the {@code protobuf} package. + * Others should not use this class directly. + * + * @author kenton@google.com (Kenton Varda) + */ +public class Internal { + + protected static final Charset UTF_8 = Charset.forName("UTF-8"); + protected static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); + + /** + * Helper called by generated code to construct default values for string + * fields. + *

+ * The protocol compiler does not actually contain a UTF-8 decoder -- it + * just pushes UTF-8-encoded text around without touching it. The one place + * where this presents a problem is when generating Java string literals. + * Unicode characters in the string literal would normally need to be encoded + * using a Unicode escape sequence, which would require decoding them. + * To get around this, protoc instead embeds the UTF-8 bytes into the + * generated code and leaves it to the runtime library to decode them. + *

+ * It gets worse, though. If protoc just generated a byte array, like: + * new byte[] {0x12, 0x34, 0x56, 0x78} + * Java actually generates *code* which allocates an array and then fills + * in each value. This is much less efficient than just embedding the bytes + * directly into the bytecode. To get around this, we need another + * work-around. String literals are embedded directly, so protoc actually + * generates a string literal corresponding to the bytes. The easiest way + * to do this is to use the ISO-8859-1 character set, which corresponds to + * the first 256 characters of the Unicode range. Protoc can then use + * good old CEscape to generate the string. + *

+ * So we have a string literal which represents a set of bytes which + * represents another string. This function -- stringDefaultValue -- + * converts from the generated string to the string we actually want. The + * generated code calls this automatically. + */ + public static String stringDefaultValue(String bytes) { + return new String(bytes.getBytes(ISO_8859_1), UTF_8); + } + + /** + * Helper called by generated code to construct default values for bytes + * fields. + *

+ * This is a lot like {@link #stringDefaultValue}, but for bytes fields. + * In this case we only need the second of the two hacks -- allowing us to + * embed raw bytes as a string literal with ISO-8859-1 encoding. + */ + public static ByteString bytesDefaultValue(String bytes) { + return ByteString.copyFrom(bytes.getBytes(ISO_8859_1)); + } + /** + * Helper called by generated code to construct default values for bytes + * fields. + *

+ * This is like {@link #bytesDefaultValue}, but returns a byte array. + */ + public static byte[] byteArrayDefaultValue(String bytes) { + return bytes.getBytes(ISO_8859_1); + } + + /** + * Helper called by generated code to construct default values for bytes + * fields. + *

+ * This is like {@link #bytesDefaultValue}, but returns a ByteBuffer. + */ + public static ByteBuffer byteBufferDefaultValue(String bytes) { + return ByteBuffer.wrap(byteArrayDefaultValue(bytes)); + } + + /** + * Create a new ByteBuffer and copy all the content of {@code source} + * ByteBuffer to the new ByteBuffer. The new ByteBuffer's limit and + * capacity will be source.capacity(), and its position will be 0. + * Note that the state of {@code source} ByteBuffer won't be changed. + */ + public static ByteBuffer copyByteBuffer(ByteBuffer source) { + // Make a duplicate of the source ByteBuffer and read data from the + // duplicate. This is to avoid affecting the source ByteBuffer's state. + ByteBuffer temp = source.duplicate(); + // We want to copy all the data in the source ByteBuffer, not just the + // remaining bytes. + temp.clear(); + ByteBuffer result = ByteBuffer.allocate(temp.capacity()); + result.put(temp); + result.clear(); + return result; + } + + /** + * Helper called by generated code to determine if a byte array is a valid + * UTF-8 encoded string such that the original bytes can be converted to + * a String object and then back to a byte array round tripping the bytes + * without loss. More precisely, returns {@code true} whenever: + *

   {@code
+   * Arrays.equals(byteString.toByteArray(),
+   *     new String(byteString.toByteArray(), "UTF-8").getBytes("UTF-8"))
+   * }
+ * + *

This method rejects "overlong" byte sequences, as well as + * 3-byte sequences that would map to a surrogate character, in + * accordance with the restricted definition of UTF-8 introduced in + * Unicode 3.1. Note that the UTF-8 decoder included in Oracle's + * JDK has been modified to also reject "overlong" byte sequences, + * but currently (2011) still accepts 3-byte surrogate character + * byte sequences. + * + *

See the Unicode Standard,
+ * Table 3-6. UTF-8 Bit Distribution,
+ * Table 3-7. Well Formed UTF-8 Byte Sequences. + * + *

As of 2011-02, this method simply returns the result of {@link + * ByteString#isValidUtf8()}. Calling that method directly is preferred. + * + * @param byteString the string to check + * @return whether the byte array is round trippable + */ + public static boolean isValidUtf8(ByteString byteString) { + return byteString.isValidUtf8(); + } + + /** + * Like {@link #isValidUtf8(ByteString)} but for byte arrays. + */ + public static boolean isValidUtf8(byte[] byteArray) { + return Utf8.isValidUtf8(byteArray); + } + + /** + * Helper method to get the UTF-8 bytes of a string. + */ + public static byte[] toByteArray(String value) { + return value.getBytes(UTF_8); + } + + /** + * Helper method to convert a byte array to a string using UTF-8 encoding. + */ + public static String toStringUtf8(byte[] bytes) { + return new String(bytes, UTF_8); + } + + /** + * Interface for an enum value or value descriptor, to be used in FieldSet. + * The lite library stores enum values directly in FieldSets but the full + * library stores EnumValueDescriptors in order to better support reflection. + */ + public interface EnumLite { + int getNumber(); + } + + /** + * Interface for an object which maps integers to {@link EnumLite}s. + * {@link Descriptors.EnumDescriptor} implements this interface by mapping + * numbers to {@link Descriptors.EnumValueDescriptor}s. Additionally, + * every generated enum type has a static method internalGetValueMap() which + * returns an implementation of this type that maps numbers to enum values. + */ + public interface EnumLiteMap { + T findValueByNumber(int number); + } + + /** + * Helper method for implementing {@link Message#hashCode()} for longs. + * @see Long#hashCode() + */ + public static int hashLong(long n) { + return (int) (n ^ (n >>> 32)); + } + + /** + * Helper method for implementing {@link Message#hashCode()} for + * booleans. + * @see Boolean#hashCode() + */ + public static int hashBoolean(boolean b) { + return b ? 1231 : 1237; + } + + /** + * Helper method for implementing {@link Message#hashCode()} for enums. + *

+ * This is needed because {@link java.lang.Enum#hashCode()} is final, but we + * need to use the field number as the hash code to ensure compatibility + * between statically and dynamically generated enum objects. + */ + public static int hashEnum(EnumLite e) { + return e.getNumber(); + } + + /** + * Helper method for implementing {@link Message#hashCode()} for + * enum lists. + */ + public static int hashEnumList(List list) { + int hash = 1; + for (EnumLite e : list) { + hash = 31 * hash + hashEnum(e); + } + return hash; + } + + /** + * Helper method for implementing {@link Message#equals(Object)} for bytes field. + */ + public static boolean equals(List a, List b) { + if (a.size() != b.size()) return false; + for (int i = 0; i < a.size(); ++i) { + if (!Arrays.equals(a.get(i), b.get(i))) { + return false; + } + } + return true; + } + + /** + * Helper method for implementing {@link Message#hashCode()} for bytes field. + */ + public static int hashCode(List list) { + int hash = 1; + for (byte[] bytes : list) { + hash = 31 * hash + hashCode(bytes); + } + return hash; + } + + /** + * Helper method for implementing {@link Message#hashCode()} for bytes field. + */ + public static int hashCode(byte[] bytes) { + // The hash code for a byte array should be the same as the hash code for a + // ByteString with the same content. This is to ensure that the generated + // hashCode() method will return the same value as the pure reflection + // based hashCode() method. + return Internal.hashCode(bytes, 0, bytes.length); + } + + /** + * Helper method for implementing {@link LiteralByteString#hashCode()}. + */ + static int hashCode(byte[] bytes, int offset, int length) { + // The hash code for a byte array should be the same as the hash code for a + // ByteString with the same content. This is to ensure that the generated + // hashCode() method will return the same value as the pure reflection + // based hashCode() method. + int h = Internal.partialHash(length, bytes, offset, length); + return h == 0 ? 1 : h; + } + + /** + * Helper method for continuously hashing bytes. + */ + static int partialHash(int h, byte[] bytes, int offset, int length) { + for (int i = offset; i < offset + length; i++) { + h = h * 31 + bytes[i]; + } + return h; + } + + /** + * Helper method for implementing {@link Message#equals(Object)} for bytes + * field. + */ + public static boolean equalsByteBuffer(ByteBuffer a, ByteBuffer b) { + if (a.capacity() != b.capacity()) { + return false; + } + // ByteBuffer.equals() will only compare the remaining bytes, but we want to + // compare all the content. + return a.duplicate().clear().equals(b.duplicate().clear()); + } + + /** + * Helper method for implementing {@link Message#equals(Object)} for bytes + * field. + */ + public static boolean equalsByteBuffer( + List a, List b) { + if (a.size() != b.size()) { + return false; + } + for (int i = 0; i < a.size(); ++i) { + if (!equalsByteBuffer(a.get(i), b.get(i))) { + return false; + } + } + return true; + } + + /** + * Helper method for implementing {@link Message#hashCode()} for bytes + * field. + */ + public static int hashCodeByteBuffer(List list) { + int hash = 1; + for (ByteBuffer bytes : list) { + hash = 31 * hash + hashCodeByteBuffer(bytes); + } + return hash; + } + + private static final int DEFAULT_BUFFER_SIZE = 4096; + + /** + * Helper method for implementing {@link Message#hashCode()} for bytes + * field. + */ + public static int hashCodeByteBuffer(ByteBuffer bytes) { + if (bytes.hasArray()) { + // Fast path. + int h = partialHash(bytes.capacity(), bytes.array(), bytes.arrayOffset(), bytes.capacity()); + return h == 0 ? 1 : h; + } else { + // Read the data into a temporary byte array before calculating the + // hash value. + final int bufferSize = bytes.capacity() > DEFAULT_BUFFER_SIZE + ? DEFAULT_BUFFER_SIZE : bytes.capacity(); + final byte[] buffer = new byte[bufferSize]; + final ByteBuffer duplicated = bytes.duplicate(); + duplicated.clear(); + int h = bytes.capacity(); + while (duplicated.remaining() > 0) { + final int length = duplicated.remaining() <= bufferSize ? + duplicated.remaining() : bufferSize; + duplicated.get(buffer, 0, length); + h = partialHash(h, buffer, 0, length); + } + return h == 0 ? 1 : h; + } + } + + @SuppressWarnings("unchecked") + public static T getDefaultInstance(Class clazz) { + try { + Method method = clazz.getMethod("getDefaultInstance"); + return (T) method.invoke(method); + } catch (Exception e) { + throw new RuntimeException( + "Failed to get default instance for " + clazz, e); + } + } + + /** + * An empty byte array constant used in generated code. + */ + public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; + + /** + * An empty byte array constant used in generated code. + */ + public static final ByteBuffer EMPTY_BYTE_BUFFER = + ByteBuffer.wrap(EMPTY_BYTE_ARRAY); + + /** An empty coded input stream constant used in generated code. */ + public static final CodedInputStream EMPTY_CODED_INPUT_STREAM = + CodedInputStream.newInstance(EMPTY_BYTE_ARRAY); + + /** + * Provides an immutable view of {@code List} around a {@code List}. + * + * Protobuf internal. Used in protobuf generated code only. + */ + public static class ListAdapter extends AbstractList { + /** + * Convert individual elements of the List from F to T. + */ + public interface Converter { + T convert(F from); + } + + private final List fromList; + private final Converter converter; + + public ListAdapter(List fromList, Converter converter) { + this.fromList = fromList; + this.converter = converter; + } + + @Override + public T get(int index) { + return converter.convert(fromList.get(index)); + } + + @Override + public int size() { + return fromList.size(); + } + } + + /** + * Wrap around a {@code Map} and provide a {@code Map} + * interface. + */ + public static class MapAdapter extends AbstractMap { + /** + * An interface used to convert between two types. + */ + public interface Converter { + B doForward(A object); + A doBackward(B object); + } + + public static Converter newEnumConverter( + final EnumLiteMap enumMap, final T unrecognizedValue) { + return new Converter() { + public T doForward(Integer value) { + T result = enumMap.findValueByNumber(value); + return result == null ? unrecognizedValue : result; + } + public Integer doBackward(T value) { + return value.getNumber(); + } + }; + } + + private final Map realMap; + private final Converter valueConverter; + + public MapAdapter(Map realMap, + Converter valueConverter) { + this.realMap = realMap; + this.valueConverter = valueConverter; + } + + @SuppressWarnings("unchecked") + @Override + public V get(Object key) { + RealValue result = realMap.get(key); + if (result == null) { + return null; + } + return valueConverter.doForward(result); + } + + @Override + public V put(K key, V value) { + RealValue oldValue = realMap.put(key, valueConverter.doBackward(value)); + if (oldValue == null) { + return null; + } + return valueConverter.doForward(oldValue); + } + + @Override + public Set> entrySet() { + return new SetAdapter(realMap.entrySet()); + } + + private class SetAdapter extends AbstractSet> { + private final Set> realSet; + public SetAdapter(Set> realSet) { + this.realSet = realSet; + } + + @Override + public Iterator> iterator() { + return new IteratorAdapter(realSet.iterator()); + } + + @Override + public int size() { + return realSet.size(); + } + } + + private class IteratorAdapter implements Iterator> { + private final Iterator> realIterator; + + public IteratorAdapter( + Iterator> realIterator) { + this.realIterator = realIterator; + } + + @Override + public boolean hasNext() { + return realIterator.hasNext(); + } + + @Override + public java.util.Map.Entry next() { + return new EntryAdapter(realIterator.next()); + } + + @Override + public void remove() { + realIterator.remove(); + } + } + + private class EntryAdapter implements Map.Entry { + private final Map.Entry realEntry; + + public EntryAdapter(Map.Entry realEntry) { + this.realEntry = realEntry; + } + + @Override + public K getKey() { + return realEntry.getKey(); + } + + @Override + public V getValue() { + return valueConverter.doForward(realEntry.getValue()); + } + + @Override + public V setValue(V value) { + RealValue oldValue = realEntry.setValue( + valueConverter.doBackward(value)); + if (oldValue == null) { + return null; + } + return valueConverter.doForward(oldValue); + } + } + } + + /** + * Extends {@link List} to add the capability to make the list immutable and inspect if it is + * modifiable. + */ + public static interface ProtobufList extends List { + + /** + * Makes this list immutable. All subsequent modifications will throw an + * {@link UnsupportedOperationException}. + */ + void makeImmutable(); + + /** + * Returns whether this list can be modified via the publicly accessible {@link List} methods. + */ + boolean isModifiable(); + } + + /** + * A {@link java.util.List} implementation that avoids boxing the elements into Integers if + * possible. Does not support null elements. + */ + public static interface IntList extends ProtobufList { + + /** + * Like {@link #get(int)} but more efficient in that it doesn't box the returned value. + */ + int getInt(int index); + + /** + * Like {@link #add(Object)} but more efficient in that it doesn't box the element. + */ + void addInt(int element); + + /** + * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. + */ + int setInt(int index, int element); + } + + /** + * A {@link java.util.List} implementation that avoids boxing the elements into Booleans if + * possible. Does not support null elements. + */ + public static interface BooleanList extends ProtobufList { + + /** + * Like {@link #get(int)} but more efficient in that it doesn't box the returned value. + */ + boolean getBoolean(int index); + + /** + * Like {@link #add(Object)} but more efficient in that it doesn't box the element. + */ + void addBoolean(boolean element); + + /** + * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. + */ + boolean setBoolean(int index, boolean element); + } + + /** + * A {@link java.util.List} implementation that avoids boxing the elements into Longs if + * possible. Does not support null elements. + */ + public static interface LongList extends ProtobufList { + + /** + * Like {@link #get(int)} but more efficient in that it doesn't box the returned value. + */ + long getLong(int index); + + /** + * Like {@link #add(Object)} but more efficient in that it doesn't box the element. + */ + void addLong(long element); + + /** + * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. + */ + long setLong(int index, long element); + } + + /** + * A {@link java.util.List} implementation that avoids boxing the elements into Doubles if + * possible. Does not support null elements. + */ + public static interface DoubleList extends ProtobufList { + + /** + * Like {@link #get(int)} but more efficient in that it doesn't box the returned value. + */ + double getDouble(int index); + + /** + * Like {@link #add(Object)} but more efficient in that it doesn't box the element. + */ + void addDouble(double element); + + /** + * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. + */ + double setDouble(int index, double element); + } + + /** + * A {@link java.util.List} implementation that avoids boxing the elements into Floats if + * possible. Does not support null elements. + */ + public static interface FloatList extends ProtobufList { + + /** + * Like {@link #get(int)} but more efficient in that it doesn't box the returned value. + */ + float getFloat(int index); + + /** + * Like {@link #add(Object)} but more efficient in that it doesn't box the element. + */ + void addFloat(float element); + + /** + * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. + */ + float setFloat(int index, float element); + } +} -- cgit v1.2.3