|
@@ -0,0 +1,176 @@
|
|
|
|
|
+// Protocol Buffers - Google's data interchange format
|
|
|
|
|
+// Copyright 2008 Google Inc. All rights reserved.
|
|
|
|
|
+// http://code.google.com/p/protobuf/
|
|
|
|
|
+//
|
|
|
|
|
+// 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 parse it on-demand.
|
|
|
|
|
+ *
|
|
|
|
|
+ * LazyField is thread-compatible e.g. concurrent read are safe, however,
|
|
|
|
|
+ * synchronizations are needed under read/write situations.
|
|
|
|
|
+ *
|
|
|
|
|
+ * This class is internal implementation detail, so you don't need to use it directly.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @author xiangl@google.com (Xiang Li)
|
|
|
|
|
+ */
|
|
|
|
|
+public class LazyFieldLite {
|
|
|
|
|
+ private ByteString bytes;
|
|
|
|
|
+ private ExtensionRegistryLite extensionRegistry;
|
|
|
|
|
+ private volatile boolean isDirty = false;
|
|
|
|
|
+
|
|
|
|
|
+ protected volatile MessageLite value;
|
|
|
|
|
+
|
|
|
|
|
+ public LazyFieldLite(ExtensionRegistryLite extensionRegistry, ByteString bytes) {
|
|
|
|
|
+ this.extensionRegistry = extensionRegistry;
|
|
|
|
|
+ this.bytes = bytes;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public LazyFieldLite() {
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static LazyFieldLite fromValue(MessageLite value) {
|
|
|
|
|
+ LazyFieldLite lf = new LazyFieldLite();
|
|
|
|
|
+ lf.setValue(value);
|
|
|
|
|
+ return lf;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public boolean containsDefaultInstance() {
|
|
|
|
|
+ return value == null && bytes == null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void clear() {
|
|
|
|
|
+ bytes = null;
|
|
|
|
|
+ value = null;
|
|
|
|
|
+ extensionRegistry = null;
|
|
|
|
|
+ isDirty = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Returns message instance. At first time, serialized data is parsed by
|
|
|
|
|
+ * {@code defaultInstance.getParserForType()}.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @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;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 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.value = value;
|
|
|
|
|
+ bytes = null;
|
|
|
|
|
+ isDirty = true;
|
|
|
|
|
+ return originalValue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void merge(LazyFieldLite value) {
|
|
|
|
|
+ if (value.containsDefaultInstance()) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (bytes == null) {
|
|
|
|
|
+ this.bytes = value.bytes;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.bytes.concat(value.toByteString());
|
|
|
|
|
+ }
|
|
|
|
|
+ isDirty = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void setByteString(ByteString bytes, ExtensionRegistryLite extensionRegistry) {
|
|
|
|
|
+ this.bytes = bytes;
|
|
|
|
|
+ this.extensionRegistry = extensionRegistry;
|
|
|
|
|
+ isDirty = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public ExtensionRegistryLite getExtensionRegistry() {
|
|
|
|
|
+ return extensionRegistry;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 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() {
|
|
|
|
|
+ if (isDirty) {
|
|
|
|
|
+ return value.getSerializedSize();
|
|
|
|
|
+ }
|
|
|
|
|
+ return bytes.size();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public ByteString toByteString() {
|
|
|
|
|
+ if (!isDirty) {
|
|
|
|
|
+ return bytes;
|
|
|
|
|
+ }
|
|
|
|
|
+ synchronized (this) {
|
|
|
|
|
+ if (!isDirty) {
|
|
|
|
|
+ return bytes;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (value == null) {
|
|
|
|
|
+ bytes = ByteString.EMPTY;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ bytes = value.toByteString();
|
|
|
|
|
+ }
|
|
|
|
|
+ isDirty = false;
|
|
|
|
|
+ return bytes;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ protected void ensureInitialized(MessageLite defaultInstance) {
|
|
|
|
|
+ if (value != null) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ synchronized (this) {
|
|
|
|
|
+ if (value != null) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (bytes != null) {
|
|
|
|
|
+ value = defaultInstance.getParserForType()
|
|
|
|
|
+ .parseFrom(bytes, extensionRegistry);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ value = defaultInstance;
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
|
+ // TODO(xiangl): Refactory the API to support the exception thrown from
|
|
|
|
|
+ // lazily load messages.
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|