diff options
Diffstat (limited to 'third_party/protobuf/3.4.0/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java')
-rw-r--r-- | third_party/protobuf/3.4.0/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/third_party/protobuf/3.4.0/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java b/third_party/protobuf/3.4.0/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java new file mode 100644 index 0000000000..49ecfc0be6 --- /dev/null +++ b/third_party/protobuf/3.4.0/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java @@ -0,0 +1,438 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import java.io.IOException; + +/** + * LazyFieldLite encapsulates the logic of lazily parsing message fields. It stores + * the message in a ByteString initially and then parses it on-demand. + * + * LazyFieldLite is thread-compatible: concurrent reads are safe once the proto that this + * LazyFieldLite is a part of is no longer being mutated by its Builder. However, explicit + * synchronization is needed under read/write situations. + * + * When a LazyFieldLite is used in the context of a MessageLite object, its behavior is considered + * to be immutable and none of the setter methods in its API are expected to be invoked. All of the + * getters are expected to be thread-safe. When used in the context of a MessageLite.Builder, + * setters can be invoked, but there is no guarantee of thread safety. + * + * TODO(yatin,dweis): Consider splitting this class's functionality and put the mutable methods + * into a separate builder class to allow us to give stronger compile-time guarantees. + * + * This class is internal implementation detail of the protobuf library, so you don't need to use it + * directly. + * + * @author xiangl@google.com (Xiang Li) + */ +public class LazyFieldLite { + private static final ExtensionRegistryLite EMPTY_REGISTRY = + ExtensionRegistryLite.getEmptyRegistry(); + + /** + * The value associated with the LazyFieldLite object is stored in one or more of the following + * three fields (delayedBytes, value, memoizedBytes). They should together be interpreted as + * follows. + * 1) delayedBytes can be non-null, while value and memoizedBytes is null. The object will be in + * this state while the value for the object has not yet been parsed. + * 2) Both delayedBytes and value are non-null. The object transitions to this state as soon as + * some caller needs to access the value (by invoking getValue()). + * 3) memoizedBytes is merely an optimization for calls to LazyFieldLite.toByteString() to avoid + * recomputing the ByteString representation on each call. Instead, when the value is parsed + * from delayedBytes, we will also assign the contents of delayedBytes to memoizedBytes (since + * that is the ByteString representation of value). + * 4) Finally, if the LazyFieldLite was created directly with a parsed MessageLite value, then + * delayedBytes will be null, and memoizedBytes will be initialized only upon the first call to + * LazyFieldLite.toByteString(). + * + * Given the above conditions, any caller that needs a serialized representation of this object + * must first check if the memoizedBytes or delayedBytes ByteString is non-null and use it + * directly; if both of those are null, it can look at the parsed value field. Similarly, any + * caller that needs a parsed value must first check if the value field is already non-null, if + * not it must parse the value from delayedBytes. + */ + + /** + * A delayed-parsed version of the contents of this field. When this field is non-null, then the + * "value" field is allowed to be null until the time that the value needs to be read. + * + * When delayedBytes is non-null then {@code extensionRegistry} is required to also be non-null. + * {@code value} and {@code memoizedBytes} will be initialized lazily. + */ + private ByteString delayedBytes; + + /** + * An {@code ExtensionRegistryLite} for parsing bytes. It is non-null on a best-effort basis. It + * is only guaranteed to be non-null if this message was initialized using bytes and an + * {@code ExtensionRegistry}. If it directly had a value set then it will be null, unless it has + * been merged with another {@code LazyFieldLite} that had an {@code ExtensionRegistry}. + */ + private ExtensionRegistryLite extensionRegistry; + + /** + * The parsed value. When this is null and a caller needs access to the MessageLite value, then + * {@code delayedBytes} will be parsed lazily at that time. + */ + protected volatile MessageLite value; + + /** + * The memoized bytes for {@code value}. This is an optimization for the toByteString() method to + * not have to recompute its return-value on each invocation. + * TODO(yatin): Figure out whether this optimization is actually necessary. + */ + private volatile ByteString memoizedBytes; + + /** + * Constructs a LazyFieldLite with bytes that will be parsed lazily. + */ + public LazyFieldLite(ExtensionRegistryLite extensionRegistry, ByteString bytes) { + checkArguments(extensionRegistry, bytes); + this.extensionRegistry = extensionRegistry; + this.delayedBytes = bytes; + } + + /** + * Constructs a LazyFieldLite with no contents, and no ability to parse extensions. + */ + public LazyFieldLite() { + } + + /** + * Constructs a LazyFieldLite instance with a value. The LazyFieldLite may not be able to parse + * the extensions in the value as it has no ExtensionRegistry. + */ + public static LazyFieldLite fromValue(MessageLite value) { + LazyFieldLite lf = new LazyFieldLite(); + lf.setValue(value); + return lf; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof LazyFieldLite)) { + return false; + } + + LazyFieldLite other = (LazyFieldLite) o; + + // Lazy fields do not work well with equals... If both are delayedBytes, we do not have a + // mechanism to deserialize them so we rely on bytes equality. Otherwise we coerce into an + // actual message (if necessary) and call equals on the message itself. This implies that two + // messages can by unequal but then be turned equal simply be invoking a getter on a lazy field. + MessageLite value1 = value; + MessageLite value2 = other.value; + if (value1 == null && value2 == null) { + return toByteString().equals(other.toByteString()); + } else if (value1 != null && value2 != null) { + return value1.equals(value2); + } else if (value1 != null) { + return value1.equals(other.getValue(value1.getDefaultInstanceForType())); + } else { + return getValue(value2.getDefaultInstanceForType()).equals(value2); + } + } + + @Override + public int hashCode() { + // We can't provide a memoizable hash code for lazy fields. The byte strings may have different + // hash codes but evaluate to equivalent messages. And we have no facility for constructing + // a message here if we were not already holding a value. + return 1; + } + + /** + * Determines whether this LazyFieldLite instance represents the default instance of this type. + */ + public boolean containsDefaultInstance() { + return memoizedBytes == ByteString.EMPTY + || value == null && (delayedBytes == null || delayedBytes == ByteString.EMPTY); + } + + /** + * Clears the value state of this instance. + * + * <p>LazyField is not thread-safe for write access. Synchronizations are needed + * under read/write situations. + */ + public void clear() { + // Don't clear the ExtensionRegistry. It might prove useful later on when merging in another + // value, but there is no guarantee that it will contain all extensions that were directly set + // on the values that need to be merged. + delayedBytes = null; + value = null; + memoizedBytes = null; + } + + /** + * Overrides the contents of this LazyField. + * + * <p>LazyField is not thread-safe for write access. Synchronizations are needed + * under read/write situations. + */ + public void set(LazyFieldLite other) { + this.delayedBytes = other.delayedBytes; + this.value = other.value; + this.memoizedBytes = other.memoizedBytes; + // If the other LazyFieldLite was created by directly setting the value rather than first by + // parsing, then it will not have an extensionRegistry. In this case we hold on to the existing + // extensionRegistry, which has no guarantees that it has all the extensions that will be + // directly set on the value. + if (other.extensionRegistry != null) { + this.extensionRegistry = other.extensionRegistry; + } + } + + /** + * Returns message instance. It may do some thread-safe delayed parsing of bytes. + * + * @param defaultInstance its message's default instance. It's also used to get parser for the + * message type. + */ + public MessageLite getValue(MessageLite defaultInstance) { + ensureInitialized(defaultInstance); + return value; + } + + /** + * Sets the value of the instance and returns the old value without delay parsing anything. + * + * <p>LazyField is not thread-safe for write access. Synchronizations are needed + * under read/write situations. + */ + public MessageLite setValue(MessageLite value) { + MessageLite originalValue = this.value; + this.delayedBytes = null; + this.memoizedBytes = null; + this.value = value; + return originalValue; + } + + /** + * Merges another instance's contents. In some cases may drop some extensions if both fields + * contain data. If the other field has an {@code ExtensionRegistry} but this does not, then this + * field will copy over that {@code ExtensionRegistry}. + * + * <p>LazyField is not thread-safe for write access. Synchronizations are needed + * under read/write situations. + */ + public void merge(LazyFieldLite other) { + if (other.containsDefaultInstance()) { + return; + } + + if (this.containsDefaultInstance()) { + set(other); + return; + } + + // If the other field has an extension registry but this does not, copy over the other extension + // registry. + if (this.extensionRegistry == null) { + this.extensionRegistry = other.extensionRegistry; + } + + // In the case that both of them are not parsed we simply concatenate the bytes to save time. In + // the (probably rare) case that they have different extension registries there is a chance that + // some of the extensions may be dropped, but the tradeoff of making this operation fast seems + // to outway the benefits of combining the extension registries, which is not normally done for + // lite protos anyways. + if (this.delayedBytes != null && other.delayedBytes != null) { + this.delayedBytes = this.delayedBytes.concat(other.delayedBytes); + return; + } + + // At least one is parsed and both contain data. We won't drop any extensions here directly, but + // in the case that the extension registries are not the same then we might in the future if we + // need to serialze and parse a message again. + if (this.value == null && other.value != null) { + setValue(mergeValueAndBytes(other.value, this.delayedBytes, this.extensionRegistry)); + return; + } else if (this.value != null && other.value == null) { + setValue(mergeValueAndBytes(this.value, other.delayedBytes, other.extensionRegistry)); + return; + } + + // At this point we have two fully parsed messages. + setValue(this.value.toBuilder().mergeFrom(other.value).build()); + } + + /** + * Merges another instance's contents from a stream. + * + * <p>LazyField is not thread-safe for write access. Synchronizations are needed + * under read/write situations. + */ + public void mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry) + throws IOException { + if (this.containsDefaultInstance()) { + setByteString(input.readBytes(), extensionRegistry); + return; + } + + // If the other field has an extension registry but this does not, copy over the other extension + // registry. + if (this.extensionRegistry == null) { + this.extensionRegistry = extensionRegistry; + } + + // In the case that both of them are not parsed we simply concatenate the bytes to save time. In + // the (probably rare) case that they have different extension registries there is a chance that + // some of the extensions may be dropped, but the tradeoff of making this operation fast seems + // to outway the benefits of combining the extension registries, which is not normally done for + // lite protos anyways. + if (this.delayedBytes != null) { + setByteString(this.delayedBytes.concat(input.readBytes()), this.extensionRegistry); + return; + } + + // We are parsed and both contain data. We won't drop any extensions here directly, but in the + // case that the extension registries are not the same then we might in the future if we + // need to serialize and parse a message again. + try { + setValue(value.toBuilder().mergeFrom(input, extensionRegistry).build()); + } catch (InvalidProtocolBufferException e) { + // Nothing is logged and no exceptions are thrown. Clients will be unaware that a proto + // was invalid. + } + } + + private static MessageLite mergeValueAndBytes( + MessageLite value, ByteString otherBytes, ExtensionRegistryLite extensionRegistry) { + try { + return value.toBuilder().mergeFrom(otherBytes, extensionRegistry).build(); + } catch (InvalidProtocolBufferException e) { + // Nothing is logged and no exceptions are thrown. Clients will be unaware that a proto + // was invalid. + return value; + } + } + + /** + * Sets this field with bytes to delay-parse. + */ + public void setByteString(ByteString bytes, ExtensionRegistryLite extensionRegistry) { + checkArguments(extensionRegistry, bytes); + this.delayedBytes = bytes; + this.extensionRegistry = extensionRegistry; + this.value = null; + this.memoizedBytes = null; + } + + /** + * Due to the optional field can be duplicated at the end of serialized + * bytes, which will make the serialized size changed after LazyField + * parsed. Be careful when using this method. + */ + public int getSerializedSize() { + // We *must* return delayed bytes size if it was ever set because the dependent messages may + // have memoized serialized size based off of it. + if (memoizedBytes != null) { + return memoizedBytes.size(); + } else if (delayedBytes != null) { + return delayedBytes.size(); + } else if (value != null) { + return value.getSerializedSize(); + } else { + return 0; + } + } + + /** + * Returns a BytesString for this field in a thread-safe way. + */ + public ByteString toByteString() { + if (memoizedBytes != null) { + return memoizedBytes; + } + // We *must* return delayed bytes if it was set because the dependent messages may have + // memoized serialized size based off of it. + if (delayedBytes != null) { + return delayedBytes; + } + synchronized (this) { + if (memoizedBytes != null) { + return memoizedBytes; + } + if (value == null) { + memoizedBytes = ByteString.EMPTY; + } else { + memoizedBytes = value.toByteString(); + } + return memoizedBytes; + } + } + + + /** + * Might lazily parse the bytes that were previously passed in. Is thread-safe. + */ + protected void ensureInitialized(MessageLite defaultInstance) { + if (value != null) { + return; + } + synchronized (this) { + if (value != null) { + return; + } + try { + if (delayedBytes != null) { + // The extensionRegistry shouldn't be null here since we have delayedBytes. + MessageLite parsedValue = defaultInstance.getParserForType() + .parseFrom(delayedBytes, extensionRegistry); + this.value = parsedValue; + this.memoizedBytes = delayedBytes; + } else { + this.value = defaultInstance; + this.memoizedBytes = ByteString.EMPTY; + } + } catch (InvalidProtocolBufferException e) { + // Nothing is logged and no exceptions are thrown. Clients will be unaware that this proto + // was invalid. + this.value = defaultInstance; + this.memoizedBytes = ByteString.EMPTY; + } + } + } + + + private static void checkArguments(ExtensionRegistryLite extensionRegistry, ByteString bytes) { + if (extensionRegistry == null) { + throw new NullPointerException("found null ExtensionRegistry"); + } + if (bytes == null) { + throw new NullPointerException("found null ByteString"); + } + } +} |