parent
80aa23df6c
commit
33165fe0d5
160 changed files with 19957 additions and 4128 deletions
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,155 @@ |
||||
// 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.util.List; |
||||
import java.util.AbstractList; |
||||
import java.util.ArrayList; |
||||
import java.util.RandomAccess; |
||||
import java.util.Collection; |
||||
|
||||
/** |
||||
* An implementation of {@link LazyStringList} that wraps an ArrayList. Each |
||||
* element is either a ByteString or a String. It caches the last one requested |
||||
* which is most likely the one needed next. This minimizes memory usage while |
||||
* satisfying the most common use cases. |
||||
* <p> |
||||
* <strong>Note that this implementation is not synchronized.</strong> |
||||
* If multiple threads access an <tt>ArrayList</tt> instance concurrently, |
||||
* and at least one of the threads modifies the list structurally, it |
||||
* <i>must</i> be synchronized externally. (A structural modification is |
||||
* any operation that adds or deletes one or more elements, or explicitly |
||||
* resizes the backing array; merely setting the value of an element is not |
||||
* a structural modification.) This is typically accomplished by |
||||
* synchronizing on some object that naturally encapsulates the list. |
||||
* <p> |
||||
* If the implementation is accessed via concurrent reads, this is thread safe. |
||||
* Conversions are done in a thread safe manner. It's possible that the |
||||
* conversion may happen more than once if two threads attempt to access the |
||||
* same element and the modifications were not visible to each other, but this |
||||
* will not result in any corruption of the list or change in behavior other |
||||
* than performance. |
||||
* |
||||
* @author jonp@google.com (Jon Perlow) |
||||
*/ |
||||
public class LazyStringArrayList extends AbstractList<String> |
||||
implements LazyStringList, RandomAccess { |
||||
|
||||
public final static LazyStringList EMPTY = new UnmodifiableLazyStringList( |
||||
new LazyStringArrayList()); |
||||
|
||||
private final List<Object> list; |
||||
|
||||
public LazyStringArrayList() { |
||||
list = new ArrayList<Object>(); |
||||
} |
||||
|
||||
public LazyStringArrayList(List<String> from) { |
||||
list = new ArrayList<Object>(from); |
||||
} |
||||
|
||||
@Override |
||||
public String get(int index) { |
||||
Object o = list.get(index); |
||||
if (o instanceof String) { |
||||
return (String) o; |
||||
} else { |
||||
ByteString bs = (ByteString) o; |
||||
String s = bs.toStringUtf8(); |
||||
if (Internal.isValidUtf8(bs)) { |
||||
list.set(index, s); |
||||
} |
||||
return s; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
return list.size(); |
||||
} |
||||
|
||||
@Override |
||||
public String set(int index, String s) { |
||||
Object o = list.set(index, s); |
||||
return asString(o); |
||||
} |
||||
|
||||
@Override |
||||
public void add(int index, String element) { |
||||
list.add(index, element); |
||||
modCount++; |
||||
} |
||||
|
||||
@Override |
||||
public boolean addAll(int index, Collection<? extends String> c) { |
||||
boolean ret = list.addAll(index, c); |
||||
modCount++; |
||||
return ret; |
||||
} |
||||
|
||||
@Override |
||||
public String remove(int index) { |
||||
Object o = list.remove(index); |
||||
modCount++; |
||||
return asString(o); |
||||
} |
||||
|
||||
public void clear() { |
||||
list.clear(); |
||||
modCount++; |
||||
} |
||||
|
||||
// @Override
|
||||
public void add(ByteString element) { |
||||
list.add(element); |
||||
modCount++; |
||||
} |
||||
|
||||
// @Override
|
||||
public ByteString getByteString(int index) { |
||||
Object o = list.get(index); |
||||
if (o instanceof String) { |
||||
ByteString b = ByteString.copyFromUtf8((String) o); |
||||
list.set(index, b); |
||||
return b; |
||||
} else { |
||||
return (ByteString) o; |
||||
} |
||||
} |
||||
|
||||
private String asString(Object o) { |
||||
if (o instanceof String) { |
||||
return (String) o; |
||||
} else { |
||||
return ((ByteString) o).toStringUtf8(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,72 @@ |
||||
// 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.util.List; |
||||
|
||||
/** |
||||
* An interface extending List<String> that also provides access to the |
||||
* items of the list as UTF8-encoded ByteString objects. This is used by the |
||||
* protocol buffer implementation to support lazily converting bytes parsed |
||||
* over the wire to String objects until needed and also increases the |
||||
* efficiency of serialization if the String was never requested as the |
||||
* ByteString is already cached. |
||||
* <p> |
||||
* This only adds additional methods that are required for the use in the |
||||
* protocol buffer code in order to be able successfuly round trip byte arrays |
||||
* through parsing and serialization without conversion to strings. It's not |
||||
* attempting to support the functionality of say List<ByteString>, hence |
||||
* why only these two very specific methods are added. |
||||
* |
||||
* @author jonp@google.com (Jon Perlow) |
||||
*/ |
||||
public interface LazyStringList extends List<String> { |
||||
|
||||
/** |
||||
* Returns the element at the specified position in this list as a ByteString. |
||||
* |
||||
* @param index index of the element to return |
||||
* @return the element at the specified position in this list |
||||
* @throws IndexOutOfBoundsException if the index is out of range |
||||
* (<tt>index < 0 || index >= size()</tt>) |
||||
*/ |
||||
ByteString getByteString(int index); |
||||
|
||||
/** |
||||
* Appends the specified element to the end of this list (optional |
||||
* operation). |
||||
* |
||||
* @param element element to be appended to this list |
||||
* @throws UnsupportedOperationException if the <tt>add</tt> operation |
||||
* is not supported by this list |
||||
*/ |
||||
void add(ByteString element); |
||||
} |
@ -0,0 +1,56 @@ |
||||
// 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; |
||||
|
||||
/** |
||||
* Base interface for methods common to {@link MessageLite} |
||||
* and {@link MessageLite.Builder} to provide type equivalency. |
||||
* |
||||
* @author jonp@google.com (Jon Perlow) |
||||
*/ |
||||
public interface MessageLiteOrBuilder { |
||||
/** |
||||
* Get an instance of the type with all fields set to their default values. |
||||
* This may or may not be a singleton. This differs from the |
||||
* {@code getDefaultInstance()} method of generated message classes in that |
||||
* this method is an abstract method of the {@code MessageLite} interface
|
||||
* whereas {@code getDefaultInstance()} is a static method of a specific |
||||
* class. They return the same thing. |
||||
*/ |
||||
MessageLite getDefaultInstanceForType(); |
||||
|
||||
/** |
||||
* Returns true if all required fields in the message and all embedded |
||||
* messages are set, false otherwise. |
||||
*/ |
||||
boolean isInitialized(); |
||||
|
||||
} |
@ -0,0 +1,110 @@ |
||||
// 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.util.Map; |
||||
|
||||
/** |
||||
* Base interface for methods common to {@link Message} and |
||||
* {@link Message.Builder} to provide type equivalency. |
||||
* |
||||
* @author jonp@google.com (Jon Perlow) |
||||
*/ |
||||
public interface MessageOrBuilder extends MessageLiteOrBuilder { |
||||
|
||||
// (From MessageLite, re-declared here only for return type covariance.)
|
||||
//@Override (Java 1.6 override semantics, but we must support 1.5)
|
||||
Message getDefaultInstanceForType(); |
||||
|
||||
/** |
||||
* Get the message's type's descriptor. This differs from the |
||||
* {@code getDescriptor()} method of generated message classes in that |
||||
* this method is an abstract method of the {@code Message} interface
|
||||
* whereas {@code getDescriptor()} is a static method of a specific class. |
||||
* They return the same thing. |
||||
*/ |
||||
Descriptors.Descriptor getDescriptorForType(); |
||||
|
||||
/** |
||||
* Returns a collection of all the fields in this message which are set |
||||
* and their corresponding values. A singular ("required" or "optional") |
||||
* field is set iff hasField() returns true for that field. A "repeated" |
||||
* field is set iff getRepeatedFieldSize() is greater than zero. The |
||||
* values are exactly what would be returned by calling |
||||
* {@link #getField(Descriptors.FieldDescriptor)} for each field. The map |
||||
* is guaranteed to be a sorted map, so iterating over it will return fields |
||||
* in order by field number. |
||||
* <br> |
||||
* If this is for a builder, the returned map may or may not reflect future |
||||
* changes to the builder. Either way, the returned map is itself |
||||
* unmodifiable. |
||||
*/ |
||||
Map<Descriptors.FieldDescriptor, Object> getAllFields(); |
||||
|
||||
/** |
||||
* Returns true if the given field is set. This is exactly equivalent to |
||||
* calling the generated "has" accessor method corresponding to the field. |
||||
* @throws IllegalArgumentException The field is a repeated field, or |
||||
* {@code field.getContainingType() != getDescriptorForType()}. |
||||
*/ |
||||
boolean hasField(Descriptors.FieldDescriptor field); |
||||
|
||||
/** |
||||
* Obtains the value of the given field, or the default value if it is |
||||
* not set. For primitive fields, the boxed primitive value is returned. |
||||
* For enum fields, the EnumValueDescriptor for the value is returend. For |
||||
* embedded message fields, the sub-message is returned. For repeated |
||||
* fields, a java.util.List is returned. |
||||
*/ |
||||
Object getField(Descriptors.FieldDescriptor field); |
||||
|
||||
/** |
||||
* Gets the number of elements of a repeated field. This is exactly |
||||
* equivalent to calling the generated "Count" accessor method corresponding |
||||
* to the field. |
||||
* @throws IllegalArgumentException The field is not a repeated field, or |
||||
* {@code field.getContainingType() != getDescriptorForType()}. |
||||
*/ |
||||
int getRepeatedFieldCount(Descriptors.FieldDescriptor field); |
||||
|
||||
/** |
||||
* Gets an element of a repeated field. For primitive fields, the boxed |
||||
* primitive value is returned. For enum fields, the EnumValueDescriptor |
||||
* for the value is returend. For embedded message fields, the sub-message |
||||
* is returned. |
||||
* @throws IllegalArgumentException The field is not a repeated field, or |
||||
* {@code field.getContainingType() != getDescriptorForType()}. |
||||
*/ |
||||
Object getRepeatedField(Descriptors.FieldDescriptor field, int index); |
||||
|
||||
/** Get the {@link UnknownFieldSet} for this message. */ |
||||
UnknownFieldSet getUnknownFields(); |
||||
} |
@ -0,0 +1,696 @@ |
||||
// 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.util.AbstractList; |
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* <code>RepeatedFieldBuilder</code> implements a structure that a protocol |
||||
* message uses to hold a repeated field of other protocol messages. It supports |
||||
* the classical use case of adding immutable {@link Message}'s to the |
||||
* repeated field and is highly optimized around this (no extra memory |
||||
* allocations and sharing of immutable arrays). |
||||
* <br> |
||||
* It also supports the additional use case of adding a {@link Message.Builder} |
||||
* to the repeated field and deferring conversion of that <code>Builder</code> |
||||
* to an immutable <code>Message</code>. In this way, it's possible to maintain |
||||
* a tree of <code>Builder</code>'s that acts as a fully read/write data |
||||
* structure. |
||||
* <br> |
||||
* Logically, one can think of a tree of builders as converting the entire tree |
||||
* to messages when build is called on the root or when any method is called |
||||
* that desires a Message instead of a Builder. In terms of the implementation, |
||||
* the <code>SingleFieldBuilder</code> and <code>RepeatedFieldBuilder</code> |
||||
* classes cache messages that were created so that messages only need to be |
||||
* created when some change occured in its builder or a builder for one of its |
||||
* descendants. |
||||
* |
||||
* @param <MType> the type of message for the field |
||||
* @param <BType> the type of builder for the field |
||||
* @param <IType> the common interface for the message and the builder |
||||
* |
||||
* @author jonp@google.com (Jon Perlow) |
||||
*/ |
||||
public class RepeatedFieldBuilder |
||||
<MType extends GeneratedMessage, |
||||
BType extends GeneratedMessage.Builder, |
||||
IType extends MessageOrBuilder> |
||||
implements GeneratedMessage.BuilderParent { |
||||
|
||||
// Parent to send changes to.
|
||||
private GeneratedMessage.BuilderParent parent; |
||||
|
||||
// List of messages. Never null. It may be immutable, in which case
|
||||
// isMessagesListImmutable will be true. See note below.
|
||||
private List<MType> messages; |
||||
|
||||
// Whether messages is an mutable array that can be modified.
|
||||
private boolean isMessagesListMutable; |
||||
|
||||
// List of builders. May be null, in which case, no nested builders were
|
||||
// created. If not null, entries represent the builder for that index.
|
||||
private List<SingleFieldBuilder<MType, BType, IType>> builders; |
||||
|
||||
// Here are the invariants for messages and builders:
|
||||
// 1. messages is never null and its count corresponds to the number of items
|
||||
// in the repeated field.
|
||||
// 2. If builders is non-null, messages and builders MUST always
|
||||
// contain the same number of items.
|
||||
// 3. Entries in either array can be null, but for any index, there MUST be
|
||||
// either a Message in messages or a builder in builders.
|
||||
// 4. If the builder at an index is non-null, the builder is
|
||||
// authoritative. This is the case where a Builder was set on the index.
|
||||
// Any message in the messages array MUST be ignored.
|
||||
// t. If the builder at an index is null, the message in the messages
|
||||
// list is authoritative. This is the case where a Message (not a Builder)
|
||||
// was set directly for an index.
|
||||
|
||||
// Indicates that we've built a message and so we are now obligated
|
||||
// to dispatch dirty invalidations. See GeneratedMessage.BuilderListener.
|
||||
private boolean isClean; |
||||
|
||||
// A view of this builder that exposes a List interface of messages. This is
|
||||
// initialized on demand. This is fully backed by this object and all changes
|
||||
// are reflected in it. Access to any item converts it to a message if it
|
||||
// was a builder.
|
||||
private MessageExternalList<MType, BType, IType> externalMessageList; |
||||
|
||||
// A view of this builder that exposes a List interface of builders. This is
|
||||
// initialized on demand. This is fully backed by this object and all changes
|
||||
// are reflected in it. Access to any item converts it to a builder if it
|
||||
// was a message.
|
||||
private BuilderExternalList<MType, BType, IType> externalBuilderList; |
||||
|
||||
// A view of this builder that exposes a List interface of the interface
|
||||
// implemented by messages and builders. This is initialized on demand. This
|
||||
// is fully backed by this object and all changes are reflected in it.
|
||||
// Access to any item returns either a builder or message depending on
|
||||
// what is most efficient.
|
||||
private MessageOrBuilderExternalList<MType, BType, IType> |
||||
externalMessageOrBuilderList; |
||||
|
||||
/** |
||||
* Constructs a new builder with an empty list of messages. |
||||
* |
||||
* @param messages the current list of messages |
||||
* @param isMessagesListMutable Whether the messages list is mutable |
||||
* @param parent a listener to notify of changes |
||||
* @param isClean whether the builder is initially marked clean |
||||
*/ |
||||
public RepeatedFieldBuilder( |
||||
List<MType> messages, |
||||
boolean isMessagesListMutable, |
||||
GeneratedMessage.BuilderParent parent, |
||||
boolean isClean) { |
||||
this.messages = messages; |
||||
this.isMessagesListMutable = isMessagesListMutable; |
||||
this.parent = parent; |
||||
this.isClean = isClean; |
||||
} |
||||
|
||||
public void dispose() { |
||||
// Null out parent so we stop sending it invalidations.
|
||||
parent = null; |
||||
} |
||||
|
||||
/** |
||||
* Ensures that the list of messages is mutable so it can be updated. If it's |
||||
* immutable, a copy is made. |
||||
*/ |
||||
private void ensureMutableMessageList() { |
||||
if (!isMessagesListMutable) { |
||||
messages = new ArrayList<MType>(messages); |
||||
isMessagesListMutable = true; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Ensures that the list of builders is not null. If it's null, the list is |
||||
* created and initialized to be the same size as the messages list with |
||||
* null entries. |
||||
*/ |
||||
private void ensureBuilders() { |
||||
if (this.builders == null) { |
||||
this.builders = |
||||
new ArrayList<SingleFieldBuilder<MType, BType, IType>>( |
||||
messages.size()); |
||||
for (int i = 0; i < messages.size(); i++) { |
||||
builders.add(null); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Gets the count of items in the list. |
||||
* |
||||
* @return the count of items in the list. |
||||
*/ |
||||
public int getCount() { |
||||
return messages.size(); |
||||
} |
||||
|
||||
/** |
||||
* Gets whether the list is empty. |
||||
* |
||||
* @return whether the list is empty |
||||
*/ |
||||
public boolean isEmpty() { |
||||
return messages.isEmpty(); |
||||
} |
||||
|
||||
/** |
||||
* Get the message at the specified index. If the message is currently stored |
||||
* as a <code>Builder</code>, it is converted to a <code>Message</code> by |
||||
* calling {@link Message.Builder#buildPartial} on it. |
||||
* |
||||
* @param index the index of the message to get |
||||
* @return the message for the specified index |
||||
*/ |
||||
public MType getMessage(int index) { |
||||
return getMessage(index, false); |
||||
} |
||||
|
||||
/** |
||||
* Get the message at the specified index. If the message is currently stored |
||||
* as a <code>Builder</code>, it is converted to a <code>Message</code> by |
||||
* calling {@link Message.Builder#buildPartial} on it. |
||||
* |
||||
* @param index the index of the message to get |
||||
* @param forBuild this is being called for build so we want to make sure |
||||
* we SingleFieldBuilder.build to send dirty invalidations |
||||
* @return the message for the specified index |
||||
*/ |
||||
private MType getMessage(int index, boolean forBuild) { |
||||
if (this.builders == null) { |
||||
// We don't have any builders -- return the current Message.
|
||||
// This is the case where no builder was created, so we MUST have a
|
||||
// Message.
|
||||
return messages.get(index); |
||||
} |
||||
|
||||
SingleFieldBuilder<MType, BType, IType> builder = builders.get(index); |
||||
if (builder == null) { |
||||
// We don't have a builder -- return the current message.
|
||||
// This is the case where no builder was created for the entry at index,
|
||||
// so we MUST have a message.
|
||||
return messages.get(index); |
||||
|
||||
} else { |
||||
return forBuild ? builder.build() : builder.getMessage(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Gets a builder for the specified index. If no builder has been created for |
||||
* that index, a builder is created on demand by calling |
||||
* {@link Message#toBuilder}. |
||||
* |
||||
* @param index the index of the message to get |
||||
* @return The builder for that index |
||||
*/ |
||||
public BType getBuilder(int index) { |
||||
ensureBuilders(); |
||||
SingleFieldBuilder<MType, BType, IType> builder = builders.get(index); |
||||
if (builder == null) { |
||||
MType message = messages.get(index); |
||||
builder = new SingleFieldBuilder<MType, BType, IType>( |
||||
message, this, isClean); |
||||
builders.set(index, builder); |
||||
} |
||||
return builder.getBuilder(); |
||||
} |
||||
|
||||
/** |
||||
* Gets the base class interface for the specified index. This may either be |
||||
* a builder or a message. It will return whatever is more efficient. |
||||
* |
||||
* @param index the index of the message to get |
||||
* @return the message or builder for the index as the base class interface |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public IType getMessageOrBuilder(int index) { |
||||
if (this.builders == null) { |
||||
// We don't have any builders -- return the current Message.
|
||||
// This is the case where no builder was created, so we MUST have a
|
||||
// Message.
|
||||
return (IType) messages.get(index); |
||||
} |
||||
|
||||
SingleFieldBuilder<MType, BType, IType> builder = builders.get(index); |
||||
if (builder == null) { |
||||
// We don't have a builder -- return the current message.
|
||||
// This is the case where no builder was created for the entry at index,
|
||||
// so we MUST have a message.
|
||||
return (IType) messages.get(index); |
||||
|
||||
} else { |
||||
return builder.getMessageOrBuilder(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Sets a message at the specified index replacing the existing item at |
||||
* that index. |
||||
* |
||||
* @param index the index to set. |
||||
* @param message the message to set |
||||
* @return the builder |
||||
*/ |
||||
public RepeatedFieldBuilder<MType, BType, IType> setMessage( |
||||
int index, MType message) { |
||||
if (message == null) { |
||||
throw new NullPointerException(); |
||||
} |
||||
ensureMutableMessageList(); |
||||
messages.set(index, message); |
||||
if (builders != null) { |
||||
SingleFieldBuilder<MType, BType, IType> entry = |
||||
builders.set(index, null); |
||||
if (entry != null) { |
||||
entry.dispose(); |
||||
} |
||||
} |
||||
onChanged(); |
||||
incrementModCounts(); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Appends the specified element to the end of this list. |
||||
* |
||||
* @param message the message to add |
||||
* @return the builder |
||||
*/ |
||||
public RepeatedFieldBuilder<MType, BType, IType> addMessage( |
||||
MType message) { |
||||
if (message == null) { |
||||
throw new NullPointerException(); |
||||
} |
||||
ensureMutableMessageList(); |
||||
messages.add(message); |
||||
if (builders != null) { |
||||
builders.add(null); |
||||
} |
||||
onChanged(); |
||||
incrementModCounts(); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Inserts the specified message at the specified position in this list. |
||||
* Shifts the element currently at that position (if any) and any subsequent |
||||
* elements to the right (adds one to their indices). |
||||
* |
||||
* @param index the index at which to insert the message |
||||
* @param message the message to add |
||||
* @return the builder |
||||
*/ |
||||
public RepeatedFieldBuilder<MType, BType, IType> addMessage( |
||||
int index, MType message) { |
||||
if (message == null) { |
||||
throw new NullPointerException(); |
||||
} |
||||
ensureMutableMessageList(); |
||||
messages.add(index, message); |
||||
if (builders != null) { |
||||
builders.add(index, null); |
||||
} |
||||
onChanged(); |
||||
incrementModCounts(); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Appends all of the messages in the specified collection to the end of |
||||
* this list, in the order that they are returned by the specified |
||||
* collection's iterator. |
||||
* |
||||
* @param values the messages to add |
||||
* @return the builder |
||||
*/ |
||||
public RepeatedFieldBuilder<MType, BType, IType> addAllMessages( |
||||
Iterable<? extends MType> values) { |
||||
for (final MType value : values) { |
||||
if (value == null) { |
||||
throw new NullPointerException(); |
||||
} |
||||
} |
||||
if (values instanceof Collection) { |
||||
@SuppressWarnings("unchecked") final |
||||
Collection<MType> collection = (Collection<MType>) values; |
||||
if (collection.size() == 0) { |
||||
return this; |
||||
} |
||||
ensureMutableMessageList(); |
||||
for (MType value : values) { |
||||
addMessage(value); |
||||
} |
||||
} else { |
||||
ensureMutableMessageList(); |
||||
for (MType value : values) { |
||||
addMessage(value); |
||||
} |
||||
} |
||||
onChanged(); |
||||
incrementModCounts(); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Appends a new builder to the end of this list and returns the builder. |
||||
* |
||||
* @param message the message to add which is the basis of the builder |
||||
* @return the new builder |
||||
*/ |
||||
public BType addBuilder(MType message) { |
||||
ensureMutableMessageList(); |
||||
ensureBuilders(); |
||||
SingleFieldBuilder<MType, BType, IType> builder = |
||||
new SingleFieldBuilder<MType, BType, IType>( |
||||
message, this, isClean); |
||||
messages.add(null); |
||||
builders.add(builder); |
||||
onChanged(); |
||||
incrementModCounts(); |
||||
return builder.getBuilder(); |
||||
} |
||||
|
||||
/** |
||||
* Inserts a new builder at the specified position in this list. |
||||
* Shifts the element currently at that position (if any) and any subsequent |
||||
* elements to the right (adds one to their indices). |
||||
* |
||||
* @param index the index at which to insert the builder |
||||
* @param message the message to add which is the basis of the builder |
||||
* @return the builder |
||||
*/ |
||||
public BType addBuilder(int index, MType message) { |
||||
ensureMutableMessageList(); |
||||
ensureBuilders(); |
||||
SingleFieldBuilder<MType, BType, IType> builder = |
||||
new SingleFieldBuilder<MType, BType, IType>( |
||||
message, this, isClean); |
||||
messages.add(index, null); |
||||
builders.add(index, builder); |
||||
onChanged(); |
||||
incrementModCounts(); |
||||
return builder.getBuilder(); |
||||
} |
||||
|
||||
/** |
||||
* Removes the element at the specified position in this list. Shifts any |
||||
* subsequent elements to the left (subtracts one from their indices). |
||||
* Returns the element that was removed from the list. |
||||
* |
||||
* @param index the index at which to remove the message |
||||
*/ |
||||
public void remove(int index) { |
||||
ensureMutableMessageList(); |
||||
messages.remove(index); |
||||
if (builders != null) { |
||||
SingleFieldBuilder<MType, BType, IType> entry = |
||||
builders.remove(index); |
||||
if (entry != null) { |
||||
entry.dispose(); |
||||
} |
||||
} |
||||
onChanged(); |
||||
incrementModCounts(); |
||||
} |
||||
|
||||
/** |
||||
* Removes all of the elements from this list. |
||||
* The list will be empty after this call returns. |
||||
*/ |
||||
public void clear() { |
||||
messages = Collections.emptyList(); |
||||
isMessagesListMutable = false; |
||||
if (builders != null) { |
||||
for (SingleFieldBuilder<MType, BType, IType> entry : |
||||
builders) { |
||||
if (entry != null) { |
||||
entry.dispose(); |
||||
} |
||||
} |
||||
builders = null; |
||||
} |
||||
onChanged(); |
||||
incrementModCounts(); |
||||
} |
||||
|
||||
/** |
||||
* Builds the list of messages from the builder and returns them. |
||||
* |
||||
* @return an immutable list of messages |
||||
*/ |
||||
public List<MType> build() { |
||||
// Now that build has been called, we are required to dispatch
|
||||
// invalidations.
|
||||
isClean = true; |
||||
|
||||
if (!isMessagesListMutable && builders == null) { |
||||
// We still have an immutable list and we never created a builder.
|
||||
return messages; |
||||
} |
||||
|
||||
boolean allMessagesInSync = true; |
||||
if (!isMessagesListMutable) { |
||||
// We still have an immutable list. Let's see if any of them are out
|
||||
// of sync with their builders.
|
||||
for (int i = 0; i < messages.size(); i++) { |
||||
Message message = messages.get(i); |
||||
SingleFieldBuilder<MType, BType, IType> builder = builders.get(i); |
||||
if (builder != null) { |
||||
if (builder.build() != message) { |
||||
allMessagesInSync = false; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
if (allMessagesInSync) { |
||||
// Immutable list is still in sync.
|
||||
return messages; |
||||
} |
||||
} |
||||
|
||||
// Need to make sure messages is up to date
|
||||
ensureMutableMessageList(); |
||||
for (int i = 0; i < messages.size(); i++) { |
||||
messages.set(i, getMessage(i, true)); |
||||
} |
||||
|
||||
// We're going to return our list as immutable so we mark that we can
|
||||
// no longer update it.
|
||||
messages = Collections.unmodifiableList(messages); |
||||
isMessagesListMutable = false; |
||||
return messages; |
||||
} |
||||
|
||||
/** |
||||
* Gets a view of the builder as a list of messages. The returned list is live |
||||
* and will reflect any changes to the underlying builder. |
||||
* |
||||
* @return the messages in the list |
||||
*/ |
||||
public List<MType> getMessageList() { |
||||
if (externalMessageList == null) { |
||||
externalMessageList = |
||||
new MessageExternalList<MType, BType, IType>(this); |
||||
} |
||||
return externalMessageList; |
||||
} |
||||
|
||||
/** |
||||
* Gets a view of the builder as a list of builders. This returned list is |
||||
* live and will reflect any changes to the underlying builder. |
||||
* |
||||
* @return the builders in the list |
||||
*/ |
||||
public List<BType> getBuilderList() { |
||||
if (externalBuilderList == null) { |
||||
externalBuilderList = |
||||
new BuilderExternalList<MType, BType, IType>(this); |
||||
} |
||||
return externalBuilderList; |
||||
} |
||||
|
||||
/** |
||||
* Gets a view of the builder as a list of MessageOrBuilders. This returned |
||||
* list is live and will reflect any changes to the underlying builder. |
||||
* |
||||
* @return the builders in the list |
||||
*/ |
||||
public List<IType> getMessageOrBuilderList() { |
||||
if (externalMessageOrBuilderList == null) { |
||||
externalMessageOrBuilderList = |
||||
new MessageOrBuilderExternalList<MType, BType, IType>(this); |
||||
} |
||||
return externalMessageOrBuilderList; |
||||
} |
||||
|
||||
/** |
||||
* Called when a the builder or one of its nested children has changed |
||||
* and any parent should be notified of its invalidation. |
||||
*/ |
||||
private void onChanged() { |
||||
if (isClean && parent != null) { |
||||
parent.markDirty(); |
||||
|
||||
// Don't keep dispatching invalidations until build is called again.
|
||||
isClean = false; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void markDirty() { |
||||
onChanged(); |
||||
} |
||||
|
||||
/** |
||||
* Increments the mod counts so that an ConcurrentModificationException can |
||||
* be thrown if calling code tries to modify the builder while its iterating |
||||
* the list. |
||||
*/ |
||||
private void incrementModCounts() { |
||||
if (externalMessageList != null) { |
||||
externalMessageList.incrementModCount(); |
||||
} |
||||
if (externalBuilderList != null) { |
||||
externalBuilderList.incrementModCount(); |
||||
} |
||||
if (externalMessageOrBuilderList != null) { |
||||
externalMessageOrBuilderList.incrementModCount(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Provides a live view of the builder as a list of messages. |
||||
* |
||||
* @param <MType> the type of message for the field |
||||
* @param <BType> the type of builder for the field |
||||
* @param <IType> the common interface for the message and the builder |
||||
*/ |
||||
private static class MessageExternalList< |
||||
MType extends GeneratedMessage, |
||||
BType extends GeneratedMessage.Builder, |
||||
IType extends MessageOrBuilder> |
||||
extends AbstractList<MType> implements List<MType> { |
||||
|
||||
RepeatedFieldBuilder<MType, BType, IType> builder; |
||||
|
||||
MessageExternalList( |
||||
RepeatedFieldBuilder<MType, BType, IType> builder) { |
||||
this.builder = builder; |
||||
} |
||||
|
||||
public int size() { |
||||
return this.builder.getCount(); |
||||
} |
||||
|
||||
public MType get(int index) { |
||||
return builder.getMessage(index); |
||||
} |
||||
|
||||
void incrementModCount() { |
||||
modCount++; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Provides a live view of the builder as a list of builders. |
||||
* |
||||
* @param <MType> the type of message for the field |
||||
* @param <BType> the type of builder for the field |
||||
* @param <IType> the common interface for the message and the builder |
||||
*/ |
||||
private static class BuilderExternalList< |
||||
MType extends GeneratedMessage, |
||||
BType extends GeneratedMessage.Builder, |
||||
IType extends MessageOrBuilder> |
||||
extends AbstractList<BType> implements List<BType> { |
||||
|
||||
RepeatedFieldBuilder<MType, BType, IType> builder; |
||||
|
||||
BuilderExternalList( |
||||
RepeatedFieldBuilder<MType, BType, IType> builder) { |
||||
this.builder = builder; |
||||
} |
||||
|
||||
public int size() { |
||||
return this.builder.getCount(); |
||||
} |
||||
|
||||
public BType get(int index) { |
||||
return builder.getBuilder(index); |
||||
} |
||||
|
||||
void incrementModCount() { |
||||
modCount++; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Provides a live view of the builder as a list of builders. |
||||
* |
||||
* @param <MType> the type of message for the field |
||||
* @param <BType> the type of builder for the field |
||||
* @param <IType> the common interface for the message and the builder |
||||
*/ |
||||
private static class MessageOrBuilderExternalList< |
||||
MType extends GeneratedMessage, |
||||
BType extends GeneratedMessage.Builder, |
||||
IType extends MessageOrBuilder> |
||||
extends AbstractList<IType> implements List<IType> { |
||||
|
||||
RepeatedFieldBuilder<MType, BType, IType> builder; |
||||
|
||||
MessageOrBuilderExternalList( |
||||
RepeatedFieldBuilder<MType, BType, IType> builder) { |
||||
this.builder = builder; |
||||
} |
||||
|
||||
public int size() { |
||||
return this.builder.getCount(); |
||||
} |
||||
|
||||
public IType get(int index) { |
||||
return builder.getMessageOrBuilder(index); |
||||
} |
||||
|
||||
void incrementModCount() { |
||||
modCount++; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,241 @@ |
||||
// 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; |
||||
|
||||
/** |
||||
* <code>SingleFieldBuilder</code> implements a structure that a protocol |
||||
* message uses to hold a single field of another protocol message. It supports |
||||
* the classical use case of setting an immutable {@link Message} as the value |
||||
* of the field and is highly optimized around this. |
||||
* <br> |
||||
* It also supports the additional use case of setting a {@link Message.Builder} |
||||
* as the field and deferring conversion of that <code>Builder</code> |
||||
* to an immutable <code>Message</code>. In this way, it's possible to maintain |
||||
* a tree of <code>Builder</code>'s that acts as a fully read/write data |
||||
* structure. |
||||
* <br> |
||||
* Logically, one can think of a tree of builders as converting the entire tree |
||||
* to messages when build is called on the root or when any method is called |
||||
* that desires a Message instead of a Builder. In terms of the implementation, |
||||
* the <code>SingleFieldBuilder</code> and <code>RepeatedFieldBuilder</code> |
||||
* classes cache messages that were created so that messages only need to be |
||||
* created when some change occured in its builder or a builder for one of its |
||||
* descendants. |
||||
* |
||||
* @param <MType> the type of message for the field |
||||
* @param <BType> the type of builder for the field |
||||
* @param <IType> the common interface for the message and the builder |
||||
* |
||||
* @author jonp@google.com (Jon Perlow) |
||||
*/ |
||||
public class SingleFieldBuilder |
||||
<MType extends GeneratedMessage, |
||||
BType extends GeneratedMessage.Builder, |
||||
IType extends MessageOrBuilder> |
||||
implements GeneratedMessage.BuilderParent { |
||||
|
||||
// Parent to send changes to.
|
||||
private GeneratedMessage.BuilderParent parent; |
||||
|
||||
// Invariant: one of builder or message fields must be non-null.
|
||||
|
||||
// If set, this is the case where we are backed by a builder. In this case,
|
||||
// message field represents a cached message for the builder (or null if
|
||||
// there is no cached message).
|
||||
private BType builder; |
||||
|
||||
// If builder is non-null, this represents a cached message from the builder.
|
||||
// If builder is null, this is the authoritative message for the field.
|
||||
private MType message; |
||||
|
||||
// Indicates that we've built a message and so we are now obligated
|
||||
// to dispatch dirty invalidations. See GeneratedMessage.BuilderListener.
|
||||
private boolean isClean; |
||||
|
||||
public SingleFieldBuilder( |
||||
MType message, |
||||
GeneratedMessage.BuilderParent parent, |
||||
boolean isClean) { |
||||
if (message == null) { |
||||
throw new NullPointerException(); |
||||
} |
||||
this.message = message; |
||||
this.parent = parent; |
||||
this.isClean = isClean; |
||||
} |
||||
|
||||
public void dispose() { |
||||
// Null out parent so we stop sending it invalidations.
|
||||
parent = null; |
||||
} |
||||
|
||||
/** |
||||
* Get the message for the field. If the message is currently stored |
||||
* as a <code>Builder</code>, it is converted to a <code>Message</code> by |
||||
* calling {@link Message.Builder#buildPartial} on it. If no message has |
||||
* been set, returns the default instance of the message. |
||||
* |
||||
* @return the message for the field |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public MType getMessage() { |
||||
if (message == null) { |
||||
// If message is null, the invariant is that we must be have a builder.
|
||||
message = (MType) builder.buildPartial(); |
||||
} |
||||
return message; |
||||
} |
||||
|
||||
/** |
||||
* Builds the message and returns it. |
||||
* |
||||
* @return the message |
||||
*/ |
||||
public MType build() { |
||||
// Now that build has been called, we are required to dispatch
|
||||
// invalidations.
|
||||
isClean = true; |
||||
return getMessage(); |
||||
} |
||||
|
||||
/** |
||||
* Gets a builder for the field. If no builder has been created yet, a |
||||
* builder is created on demand by calling {@link Message#toBuilder}. |
||||
* |
||||
* @return The builder for the field |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public BType getBuilder() { |
||||
if (builder == null) { |
||||
// builder.mergeFrom() on a fresh builder
|
||||
// does not create any sub-objects with independent clean/dirty states,
|
||||
// therefore setting the builder itself to clean without actually calling
|
||||
// build() cannot break any invariants.
|
||||
builder = (BType) message.newBuilderForType(this); |
||||
builder.mergeFrom(message); // no-op if message is the default message
|
||||
builder.markClean(); |
||||
} |
||||
return builder; |
||||
} |
||||
|
||||
/** |
||||
* Gets the base class interface for the field. This may either be a builder |
||||
* or a message. It will return whatever is more efficient. |
||||
* |
||||
* @return the message or builder for the field as the base class interface |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public IType getMessageOrBuilder() { |
||||
if (builder != null) { |
||||
return (IType) builder; |
||||
} else { |
||||
return (IType) message; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Sets a message for the field replacing any existing value. |
||||
* |
||||
* @param message the message to set |
||||
* @return the builder |
||||
*/ |
||||
public SingleFieldBuilder<MType, BType, IType> setMessage( |
||||
MType message) { |
||||
if (message == null) { |
||||
throw new NullPointerException(); |
||||
} |
||||
this.message = message; |
||||
if (builder != null) { |
||||
builder.dispose(); |
||||
builder = null; |
||||
} |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Merges the field from another field. |
||||
* |
||||
* @param value the value to merge from |
||||
* @return the builder |
||||
*/ |
||||
public SingleFieldBuilder<MType, BType, IType> mergeFrom( |
||||
MType value) { |
||||
if (builder == null && message == message.getDefaultInstanceForType()) { |
||||
message = value; |
||||
} else { |
||||
getBuilder().mergeFrom(value); |
||||
} |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Clears the value of the field. |
||||
* |
||||
* @return the builder |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public SingleFieldBuilder<MType, BType, IType> clear() { |
||||
message = (MType) (message != null ? |
||||
message.getDefaultInstanceForType() : |
||||
builder.getDefaultInstanceForType()); |
||||
if (builder != null) { |
||||
builder.dispose(); |
||||
builder = null; |
||||
} |
||||
onChanged(); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Called when a the builder or one of its nested children has changed |
||||
* and any parent should be notified of its invalidation. |
||||
*/ |
||||
private void onChanged() { |
||||
// If builder is null, this is the case where onChanged is being called
|
||||
// from setMessage or clear.
|
||||
if (builder != null) { |
||||
message = null; |
||||
} |
||||
if (isClean && parent != null) { |
||||
parent.markDirty(); |
||||
|
||||
// Don't keep dispatching invalidations until build is called again.
|
||||
isClean = false; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void markDirty() { |
||||
onChanged(); |
||||
} |
||||
} |
@ -0,0 +1,618 @@ |
||||
// 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.util.AbstractMap; |
||||
import java.util.AbstractSet; |
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.Iterator; |
||||
import java.util.TreeMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.NoSuchElementException; |
||||
import java.util.Set; |
||||
import java.util.SortedMap; |
||||
|
||||
/** |
||||
* A custom map implementation from FieldDescriptor to Object optimized to |
||||
* minimize the number of memory allocations for instances with a small number |
||||
* of mappings. The implementation stores the first {@code k} mappings in an |
||||
* array for a configurable value of {@code k}, allowing direct access to the |
||||
* corresponding {@code Entry}s without the need to create an Iterator. The |
||||
* remaining entries are stored in an overflow map. Iteration over the entries |
||||
* in the map should be done as follows: |
||||
* |
||||
* <pre> |
||||
* for (int i = 0; i < fieldMap.getNumArrayEntries(); i++) { |
||||
* process(fieldMap.getArrayEntryAt(i)); |
||||
* } |
||||
* for (Map.Entry<K, V> entry : fieldMap.getOverflowEntries()) { |
||||
* process(entry); |
||||
* } |
||||
* </pre> |
||||
* |
||||
* The resulting iteration is in order of ascending field tag number. The |
||||
* object returned by {@link #entrySet()} adheres to the same contract but is |
||||
* less efficient as it necessarily involves creating an object for iteration. |
||||
* <p> |
||||
* The tradeoff for this memory efficiency is that the worst case running time |
||||
* of the {@code put()} operation is {@code O(k + lg n)}, which happens when |
||||
* entries are added in descending order. {@code k} should be chosen such that |
||||
* it covers enough common cases without adversely affecting larger maps. In |
||||
* practice, the worst case scenario does not happen for extensions because |
||||
* extension fields are serialized and deserialized in order of ascending tag |
||||
* number, but the worst case scenario can happen for DynamicMessages. |
||||
* <p> |
||||
* The running time for all other operations is similar to that of |
||||
* {@code TreeMap}. |
||||
* <p> |
||||
* Instances are not thread-safe until {@link #makeImmutable()} is called, |
||||
* after which any modifying operation will result in an |
||||
* {@link UnsupportedOperationException}. |
||||
* |
||||
* @author darick@google.com Darick Tong |
||||
*/ |
||||
// This class is final for all intents and purposes because the constructor is
|
||||
// private. However, the FieldDescriptor-specific logic is encapsulated in
|
||||
// a subclass to aid testability of the core logic.
|
||||
class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> { |
||||
|
||||
/** |
||||
* Creates a new instance for mapping FieldDescriptors to their values. |
||||
* The {@link #makeImmutable()} implementation will convert the List values |
||||
* of any repeated fields to unmodifiable lists. |
||||
* |
||||
* @param arraySize The size of the entry array containing the |
||||
* lexicographically smallest mappings. |
||||
*/ |
||||
static <FieldDescriptorType extends |
||||
FieldSet.FieldDescriptorLite<FieldDescriptorType>> |
||||
SmallSortedMap<FieldDescriptorType, Object> newFieldMap(int arraySize) { |
||||
return new SmallSortedMap<FieldDescriptorType, Object>(arraySize) { |
||||
@Override |
||||
@SuppressWarnings("unchecked") |
||||
public void makeImmutable() { |
||||
if (!isImmutable()) { |
||||
for (int i = 0; i < getNumArrayEntries(); i++) { |
||||
final Map.Entry<FieldDescriptorType, Object> entry = |
||||
getArrayEntryAt(i); |
||||
if (entry.getKey().isRepeated()) { |
||||
final List value = (List) entry.getValue(); |
||||
entry.setValue(Collections.unmodifiableList(value)); |
||||
} |
||||
} |
||||
for (Map.Entry<FieldDescriptorType, Object> entry : |
||||
getOverflowEntries()) { |
||||
if (entry.getKey().isRepeated()) { |
||||
final List value = (List) entry.getValue(); |
||||
entry.setValue(Collections.unmodifiableList(value)); |
||||
} |
||||
} |
||||
} |
||||
super.makeImmutable(); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* Creates a new instance for testing. |
||||
* |
||||
* @param arraySize The size of the entry array containing the |
||||
* lexicographically smallest mappings. |
||||
*/ |
||||
static <K extends Comparable<K>, V> SmallSortedMap<K, V> newInstanceForTest( |
||||
int arraySize) { |
||||
return new SmallSortedMap<K, V>(arraySize); |
||||
} |
||||
|
||||
private final int maxArraySize; |
||||
// The "entry array" is actually a List because generic arrays are not
|
||||
// allowed. ArrayList also nicely handles the entry shifting on inserts and
|
||||
// removes.
|
||||
private List<Entry> entryList; |
||||
private Map<K, V> overflowEntries; |
||||
private boolean isImmutable; |
||||
// The EntrySet is a stateless view of the Map. It's initialized the first
|
||||
// time it is requested and reused henceforth.
|
||||
private volatile EntrySet lazyEntrySet; |
||||
|
||||
/** |
||||
* @code arraySize Size of the array in which the lexicographically smallest |
||||
* mappings are stored. (i.e. the {@code k} referred to in the class
|
||||
* documentation). |
||||
*/ |
||||
private SmallSortedMap(int arraySize) { |
||||
this.maxArraySize = arraySize; |
||||
this.entryList = Collections.emptyList(); |
||||
this.overflowEntries = Collections.emptyMap(); |
||||
} |
||||
|
||||
/** Make this map immutable from this point forward. */ |
||||
public void makeImmutable() { |
||||
if (!isImmutable) { |
||||
// Note: There's no need to wrap the entryList in an unmodifiableList
|
||||
// because none of the list's accessors are exposed. The iterator() of
|
||||
// overflowEntries, on the other hand, is exposed so it must be made
|
||||
// unmodifiable.
|
||||
overflowEntries = overflowEntries.isEmpty() ? |
||||
Collections.<K, V>emptyMap() : |
||||
Collections.unmodifiableMap(overflowEntries); |
||||
isImmutable = true; |
||||
} |
||||
} |
||||
|
||||
/** @return Whether {@link #makeImmutable()} has been called. */ |
||||
public boolean isImmutable() { |
||||
return isImmutable; |
||||
} |
||||
|
||||
/** @return The number of entries in the entry array. */ |
||||
public int getNumArrayEntries() { |
||||
return entryList.size(); |
||||
} |
||||
|
||||
/** @return The array entry at the given {@code index}. */ |
||||
public Map.Entry<K, V> getArrayEntryAt(int index) { |
||||
return entryList.get(index); |
||||
} |
||||
|
||||
/** @return There number of overflow entries. */ |
||||
public int getNumOverflowEntries() { |
||||
return overflowEntries.size(); |
||||
} |
||||
|
||||
/** @return An iterable over the overflow entries. */ |
||||
public Iterable<Map.Entry<K, V>> getOverflowEntries() { |
||||
return overflowEntries.isEmpty() ? |
||||
EmptySet.<Map.Entry<K, V>>iterable() : |
||||
overflowEntries.entrySet(); |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
return entryList.size() + overflowEntries.size(); |
||||
} |
||||
|
||||
/** |
||||
* The implementation throws a {@code ClassCastException} if o is not an |
||||
* object of type {@code K}. |
||||
* |
||||
* {@inheritDoc} |
||||
*/ |
||||
@Override |
||||
public boolean containsKey(Object o) { |
||||
@SuppressWarnings("unchecked") |
||||
final K key = (K) o; |
||||
return binarySearchInArray(key) >= 0 || overflowEntries.containsKey(key); |
||||
} |
||||
|
||||
/** |
||||
* The implementation throws a {@code ClassCastException} if o is not an |
||||
* object of type {@code K}. |
||||
* |
||||
* {@inheritDoc} |
||||
*/ |
||||
@Override |
||||
public V get(Object o) { |
||||
@SuppressWarnings("unchecked") |
||||
final K key = (K) o; |
||||
final int index = binarySearchInArray(key); |
||||
if (index >= 0) { |
||||
return entryList.get(index).getValue(); |
||||
} |
||||
return overflowEntries.get(key); |
||||
} |
||||
|
||||
@Override |
||||
public V put(K key, V value) { |
||||
checkMutable(); |
||||
final int index = binarySearchInArray(key); |
||||
if (index >= 0) { |
||||
// Replace existing array entry.
|
||||
return entryList.get(index).setValue(value); |
||||
} |
||||
ensureEntryArrayMutable(); |
||||
final int insertionPoint = -(index + 1); |
||||
if (insertionPoint >= maxArraySize) { |
||||
// Put directly in overflow.
|
||||
return getOverflowEntriesMutable().put(key, value); |
||||
} |
||||
// Insert new Entry in array.
|
||||
if (entryList.size() == maxArraySize) { |
||||
// Shift the last array entry into overflow.
|
||||
final Entry lastEntryInArray = entryList.remove(maxArraySize - 1); |
||||
getOverflowEntriesMutable().put(lastEntryInArray.getKey(), |
||||
lastEntryInArray.getValue()); |
||||
} |
||||
entryList.add(insertionPoint, new Entry(key, value)); |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public void clear() { |
||||
checkMutable(); |
||||
if (!entryList.isEmpty()) { |
||||
entryList.clear(); |
||||
} |
||||
if (!overflowEntries.isEmpty()) { |
||||
overflowEntries.clear(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* The implementation throws a {@code ClassCastException} if o is not an |
||||
* object of type {@code K}. |
||||
* |
||||
* {@inheritDoc} |
||||
*/ |
||||
@Override |
||||
public V remove(Object o) { |
||||
checkMutable(); |
||||
@SuppressWarnings("unchecked") |
||||
final K key = (K) o; |
||||
final int index = binarySearchInArray(key); |
||||
if (index >= 0) { |
||||
return removeArrayEntryAt(index); |
||||
} |
||||
// overflowEntries might be Collections.unmodifiableMap(), so only
|
||||
// call remove() if it is non-empty.
|
||||
if (overflowEntries.isEmpty()) { |
||||
return null; |
||||
} else { |
||||
return overflowEntries.remove(key); |
||||
} |
||||
} |
||||
|
||||
private V removeArrayEntryAt(int index) { |
||||
checkMutable(); |
||||
final V removed = entryList.remove(index).getValue(); |
||||
if (!overflowEntries.isEmpty()) { |
||||
// Shift the first entry in the overflow to be the last entry in the
|
||||
// array.
|
||||
final Iterator<Map.Entry<K, V>> iterator = |
||||
getOverflowEntriesMutable().entrySet().iterator(); |
||||
entryList.add(new Entry(iterator.next())); |
||||
iterator.remove(); |
||||
} |
||||
return removed; |
||||
} |
||||
|
||||
/** |
||||
* @param key The key to find in the entry array. |
||||
* @return The returned integer position follows the same semantics as the |
||||
* value returned by {@link java.util.Arrays#binarySearch()}. |
||||
*/ |
||||
private int binarySearchInArray(K key) { |
||||
int left = 0; |
||||
int right = entryList.size() - 1; |
||||
|
||||
// Optimization: For the common case in which entries are added in
|
||||
// ascending tag order, check the largest element in the array before
|
||||
// doing a full binary search.
|
||||
if (right >= 0) { |
||||
int cmp = key.compareTo(entryList.get(right).getKey()); |
||||
if (cmp > 0) { |
||||
return -(right + 2); // Insert point is after "right".
|
||||
} else if (cmp == 0) { |
||||
return right; |
||||
} |
||||
} |
||||
|
||||
while (left <= right) { |
||||
int mid = (left + right) / 2; |
||||
int cmp = key.compareTo(entryList.get(mid).getKey()); |
||||
if (cmp < 0) { |
||||
right = mid - 1; |
||||
} else if (cmp > 0) { |
||||
left = mid + 1; |
||||
} else { |
||||
return mid; |
||||
} |
||||
} |
||||
return -(left + 1); |
||||
} |
||||
|
||||
/** |
||||
* Similar to the AbstractMap implementation of {@code keySet()} and |
||||
* {@code values()}, the entry set is created the first time this method is |
||||
* called, and returned in response to all subsequent calls. |
||||
* |
||||
* {@inheritDoc} |
||||
*/ |
||||
@Override |
||||
public Set<Map.Entry<K, V>> entrySet() { |
||||
if (lazyEntrySet == null) { |
||||
lazyEntrySet = new EntrySet(); |
||||
} |
||||
return lazyEntrySet; |
||||
} |
||||
|
||||
/** |
||||
* @throws UnsupportedOperationException if {@link #makeImmutable()} has |
||||
* has been called. |
||||
*/ |
||||
private void checkMutable() { |
||||
if (isImmutable) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @return a {@link SortedMap} to which overflow entries mappings can be |
||||
* added or removed. |
||||
* @throws UnsupportedOperationException if {@link #makeImmutable()} has been |
||||
* called. |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
private SortedMap<K, V> getOverflowEntriesMutable() { |
||||
checkMutable(); |
||||
if (overflowEntries.isEmpty() && !(overflowEntries instanceof TreeMap)) { |
||||
overflowEntries = new TreeMap<K, V>(); |
||||
} |
||||
return (SortedMap<K, V>) overflowEntries; |
||||
} |
||||
|
||||
/** |
||||
* Lazily creates the entry list. Any code that adds to the list must first |
||||
* call this method. |
||||
*/ |
||||
private void ensureEntryArrayMutable() { |
||||
checkMutable(); |
||||
if (entryList.isEmpty() && !(entryList instanceof ArrayList)) { |
||||
entryList = new ArrayList<Entry>(maxArraySize); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Entry implementation that implements Comparable in order to support |
||||
* binary search witin the entry array. Also checks mutability in |
||||
* {@link #setValue()}. |
||||
*/ |
||||
private class Entry implements Map.Entry<K, V>, Comparable<Entry> { |
||||
|
||||
private final K key; |
||||
private V value; |
||||
|
||||
Entry(Map.Entry<K, V> copy) { |
||||
this(copy.getKey(), copy.getValue()); |
||||
} |
||||
|
||||
Entry(K key, V value) { |
||||
this.key = key; |
||||
this.value = value; |
||||
} |
||||
|
||||
@Override |
||||
public K getKey() { |
||||
return key; |
||||
} |
||||
|
||||
@Override |
||||
public V getValue() { |
||||
return value; |
||||
} |
||||
|
||||
@Override |
||||
public int compareTo(Entry other) { |
||||
return getKey().compareTo(other.getKey()); |
||||
} |
||||
|
||||
@Override |
||||
public V setValue(V newValue) { |
||||
checkMutable(); |
||||
final V oldValue = this.value; |
||||
this.value = newValue; |
||||
return oldValue; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (o == this) { |
||||
return true; |
||||
} |
||||
if (!(o instanceof Map.Entry)) { |
||||
return false; |
||||
} |
||||
@SuppressWarnings("unchecked") |
||||
Map.Entry<?, ?> other = (Map.Entry<?, ?>) o; |
||||
return equals(key, other.getKey()) && equals(value, other.getValue()); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return (key == null ? 0 : key.hashCode()) ^ |
||||
(value == null ? 0 : value.hashCode()); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return key + "=" + value; |
||||
} |
||||
|
||||
/** equals() that handles null values. */ |
||||
private boolean equals(Object o1, Object o2) { |
||||
return o1 == null ? o2 == null : o1.equals(o2); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Stateless view of the entries in the field map. |
||||
*/ |
||||
private class EntrySet extends AbstractSet<Map.Entry<K, V>> { |
||||
|
||||
@Override |
||||
public Iterator<Map.Entry<K, V>> iterator() { |
||||
return new EntryIterator(); |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
return SmallSortedMap.this.size(); |
||||
} |
||||
|
||||
/** |
||||
* Throws a {@link ClassCastException} if o is not of the expected type. |
||||
* |
||||
* {@inheritDoc} |
||||
*/ |
||||
@Override |
||||
public boolean contains(Object o) { |
||||
@SuppressWarnings("unchecked") |
||||
final Map.Entry<K, V> entry = (Map.Entry<K, V>) o; |
||||
final V existing = get(entry.getKey()); |
||||
final V value = entry.getValue(); |
||||
return existing == value || |
||||
(existing != null && existing.equals(value)); |
||||
} |
||||
|
||||
@Override |
||||
public boolean add(Map.Entry<K, V> entry) { |
||||
if (!contains(entry)) { |
||||
put(entry.getKey(), entry.getValue()); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Throws a {@link ClassCastException} if o is not of the expected type. |
||||
* |
||||
* {@inheritDoc} |
||||
*/ |
||||
@Override |
||||
public boolean remove(Object o) { |
||||
@SuppressWarnings("unchecked") |
||||
final Map.Entry<K, V> entry = (Map.Entry<K, V>) o; |
||||
if (contains(entry)) { |
||||
SmallSortedMap.this.remove(entry.getKey()); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public void clear() { |
||||
SmallSortedMap.this.clear(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Iterator implementation that switches from the entry array to the overflow |
||||
* entries appropriately. |
||||
*/ |
||||
private class EntryIterator implements Iterator<Map.Entry<K, V>> { |
||||
|
||||
private int pos = -1; |
||||
private boolean nextCalledBeforeRemove; |
||||
private Iterator<Map.Entry<K, V>> lazyOverflowIterator; |
||||
|
||||
@Override |
||||
public boolean hasNext() { |
||||
return (pos + 1) < entryList.size() || |
||||
getOverflowIterator().hasNext(); |
||||
} |
||||
|
||||
@Override |
||||
public Map.Entry<K, V> next() { |
||||
nextCalledBeforeRemove = true; |
||||
// Always increment pos so that we know whether the last returned value
|
||||
// was from the array or from overflow.
|
||||
if (++pos < entryList.size()) { |
||||
return entryList.get(pos); |
||||
} |
||||
return getOverflowIterator().next(); |
||||
} |
||||
|
||||
@Override |
||||
public void remove() { |
||||
if (!nextCalledBeforeRemove) { |
||||
throw new IllegalStateException("remove() was called before next()"); |
||||
} |
||||
nextCalledBeforeRemove = false; |
||||
checkMutable(); |
||||
|
||||
if (pos < entryList.size()) { |
||||
removeArrayEntryAt(pos--); |
||||
} else { |
||||
getOverflowIterator().remove(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* It is important to create the overflow iterator only after the array |
||||
* entries have been iterated over because the overflow entry set changes |
||||
* when the client calls remove() on the array entries, which invalidates |
||||
* any existing iterators. |
||||
*/ |
||||
private Iterator<Map.Entry<K, V>> getOverflowIterator() { |
||||
if (lazyOverflowIterator == null) { |
||||
lazyOverflowIterator = overflowEntries.entrySet().iterator(); |
||||
} |
||||
return lazyOverflowIterator; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Helper class that holds immutable instances of an Iterable/Iterator that |
||||
* we return when the overflow entries is empty. This eliminates the creation |
||||
* of an Iterator object when there is nothing to iterate over. |
||||
*/ |
||||
private static class EmptySet { |
||||
|
||||
private static final Iterator<Object> ITERATOR = new Iterator<Object>() { |
||||
@Override |
||||
public boolean hasNext() { |
||||
return false; |
||||
} |
||||
@Override |
||||
public Object next() { |
||||
throw new NoSuchElementException(); |
||||
} |
||||
@Override |
||||
public void remove() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
}; |
||||
|
||||
private static final Iterable<Object> ITERABLE = new Iterable<Object>() { |
||||
@Override |
||||
public Iterator<Object> iterator() { |
||||
return ITERATOR; |
||||
} |
||||
}; |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
static <T> Iterable<T> iterable() { |
||||
return (Iterable<T>) ITERABLE; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,146 @@ |
||||
// 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.util.AbstractList; |
||||
import java.util.RandomAccess; |
||||
import java.util.ListIterator; |
||||
import java.util.Iterator; |
||||
|
||||
/** |
||||
* An implementation of {@link LazyStringList} that wraps another |
||||
* {@link LazyStringList} such that it cannot be modified via the wrapper. |
||||
* |
||||
* @author jonp@google.com (Jon Perlow) |
||||
*/ |
||||
public class UnmodifiableLazyStringList extends AbstractList<String> |
||||
implements LazyStringList, RandomAccess { |
||||
|
||||
private final LazyStringList list; |
||||
|
||||
public UnmodifiableLazyStringList(LazyStringList list) { |
||||
this.list = list; |
||||
} |
||||
|
||||
@Override |
||||
public String get(int index) { |
||||
return list.get(index); |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
return list.size(); |
||||
} |
||||
|
||||
@Override |
||||
public ByteString getByteString(int index) { |
||||
return list.getByteString(index); |
||||
} |
||||
|
||||
@Override |
||||
public void add(ByteString element) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public ListIterator<String> listIterator(final int index) { |
||||
return new ListIterator<String>() { |
||||
ListIterator<String> iter = list.listIterator(index); |
||||
|
||||
@Override |
||||
public boolean hasNext() { |
||||
return iter.hasNext(); |
||||
} |
||||
|
||||
@Override |
||||
public String next() { |
||||
return iter.next(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean hasPrevious() { |
||||
return iter.hasPrevious(); |
||||
} |
||||
|
||||
@Override |
||||
public String previous() { |
||||
return iter.previous(); |
||||
} |
||||
|
||||
@Override |
||||
public int nextIndex() { |
||||
return iter.nextIndex(); |
||||
} |
||||
|
||||
@Override |
||||
public int previousIndex() { |
||||
return iter.previousIndex(); |
||||
} |
||||
|
||||
@Override |
||||
public void remove() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public void set(String o) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public void add(String o) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
@Override |
||||
public Iterator<String> iterator() { |
||||
return new Iterator<String>() { |
||||
Iterator<String> iter = list.iterator(); |
||||
|
||||
@Override |
||||
public boolean hasNext() { |
||||
return iter.hasNext(); |
||||
} |
||||
|
||||
@Override |
||||
public String next() { |
||||
return iter.next(); |
||||
} |
||||
|
||||
@Override |
||||
public void remove() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,80 @@ |
||||
// 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 protobuf_unittest.UnittestProto.TestDeprecatedFields; |
||||
|
||||
import junit.framework.TestCase; |
||||
|
||||
import java.lang.reflect.AnnotatedElement; |
||||
import java.lang.reflect.Method; |
||||
/** |
||||
* Test field deprecation |
||||
* |
||||
* @author birdo@google.com (Roberto Scaramuzzi) |
||||
*/ |
||||
public class DeprecatedFieldTest extends TestCase { |
||||
private String[] deprecatedGetterNames = { |
||||
"hasDeprecatedInt32", |
||||
"getDeprecatedInt32"}; |
||||
|
||||
private String[] deprecatedBuilderGetterNames = { |
||||
"hasDeprecatedInt32", |
||||
"getDeprecatedInt32", |
||||
"clearDeprecatedInt32"}; |
||||
|
||||
private String[] deprecatedBuilderSetterNames = { |
||||
"setDeprecatedInt32"}; |
||||
|
||||
public void testDeprecatedField() throws Exception { |
||||
Class<?> deprecatedFields = TestDeprecatedFields.class; |
||||
Class<?> deprecatedFieldsBuilder = TestDeprecatedFields.Builder.class; |
||||
for (String name : deprecatedGetterNames) { |
||||
Method method = deprecatedFields.getMethod(name); |
||||
assertTrue("Method " + name + " should be deprecated", |
||||
isDeprecated(method)); |
||||
} |
||||
for (String name : deprecatedBuilderGetterNames) { |
||||
Method method = deprecatedFieldsBuilder.getMethod(name); |
||||
assertTrue("Method " + name + " should be deprecated", |
||||
isDeprecated(method)); |
||||
} |
||||
for (String name : deprecatedBuilderSetterNames) { |
||||
Method method = deprecatedFieldsBuilder.getMethod(name, int.class); |
||||
assertTrue("Method " + name + " should be deprecated", |
||||
isDeprecated(method)); |
||||
} |
||||
} |
||||
|
||||
private boolean isDeprecated(AnnotatedElement annotated) { |
||||
return annotated.isAnnotationPresent(Deprecated.class); |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
// 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; |
||||
|
||||
/** |
||||
* A prerun for a test suite that allows running the full protocol buffer |
||||
* tests in a mode that disables the optimization for not using |
||||
* {@link RepeatedFieldBuilder} and {@link SingleFieldBuilder} until they are |
||||
* requested. This allows us to run all the tests through both code paths |
||||
* and ensures that both code paths produce identical results. |
||||
* |
||||
* @author jonp@google.com (Jon Perlow) |
||||
*/ |
||||
public class ForceFieldBuildersPreRun implements Runnable { |
||||
|
||||
@Override |
||||
public void run() { |
||||
GeneratedMessage.enableAlwaysUseFieldBuildersForTesting(); |
||||
} |
||||
} |
@ -0,0 +1,118 @@ |
||||
// 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 junit.framework.TestCase; |
||||
|
||||
/** |
||||
* Tests for {@link LazyStringArrayList}. |
||||
* |
||||
* @author jonp@google.com (Jon Perlow) |
||||
*/ |
||||
public class LazyStringArrayListTest extends TestCase { |
||||
|
||||
private static String STRING_A = "A"; |
||||
private static String STRING_B = "B"; |
||||
private static String STRING_C = "C"; |
||||
|
||||
private static ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A"); |
||||
private static ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B"); |
||||
private static ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C"); |
||||
|
||||
public void testJustStrings() { |
||||
LazyStringArrayList list = new LazyStringArrayList(); |
||||
list.add(STRING_A); |
||||
list.add(STRING_B); |
||||
list.add(STRING_C); |
||||
|
||||
assertEquals(3, list.size()); |
||||
assertSame(STRING_A, list.get(0)); |
||||
assertSame(STRING_B, list.get(1)); |
||||
assertSame(STRING_C, list.get(2)); |
||||
|
||||
list.set(1, STRING_C); |
||||
assertSame(STRING_C, list.get(1)); |
||||
|
||||
list.remove(1); |
||||
assertSame(STRING_A, list.get(0)); |
||||
assertSame(STRING_C, list.get(1)); |
||||
} |
||||
|
||||
public void testJustByteString() { |
||||
LazyStringArrayList list = new LazyStringArrayList(); |
||||
list.add(BYTE_STRING_A); |
||||
list.add(BYTE_STRING_B); |
||||
list.add(BYTE_STRING_C); |
||||
|
||||
assertEquals(3, list.size()); |
||||
assertSame(BYTE_STRING_A, list.getByteString(0)); |
||||
assertSame(BYTE_STRING_B, list.getByteString(1)); |
||||
assertSame(BYTE_STRING_C, list.getByteString(2)); |
||||
|
||||
list.remove(1); |
||||
assertSame(BYTE_STRING_A, list.getByteString(0)); |
||||
assertSame(BYTE_STRING_C, list.getByteString(1)); |
||||
} |
||||
|
||||
public void testConversionBackAndForth() { |
||||
LazyStringArrayList list = new LazyStringArrayList(); |
||||
list.add(STRING_A); |
||||
list.add(BYTE_STRING_B); |
||||
list.add(BYTE_STRING_C); |
||||
|
||||
// String a should be the same because it was originally a string
|
||||
assertSame(STRING_A, list.get(0)); |
||||
|
||||
// String b and c should be different because the string has to be computed
|
||||
// from the ByteString
|
||||
String bPrime = list.get(1); |
||||
assertNotSame(STRING_B, bPrime); |
||||
assertEquals(STRING_B, bPrime); |
||||
String cPrime = list.get(2); |
||||
assertNotSame(STRING_C, cPrime); |
||||
assertEquals(STRING_C, cPrime); |
||||
|
||||
// String c and c should stay the same once cached.
|
||||
assertSame(bPrime, list.get(1)); |
||||
assertSame(cPrime, list.get(2)); |
||||
|
||||
// ByteString needs to be computed from string for both a and b
|
||||
ByteString aPrimeByteString = list.getByteString(0); |
||||
assertEquals(BYTE_STRING_A, aPrimeByteString); |
||||
ByteString bPrimeByteString = list.getByteString(1); |
||||
assertNotSame(BYTE_STRING_B, bPrimeByteString); |
||||
assertEquals(BYTE_STRING_B, list.getByteString(1)); |
||||
|
||||
// Once cached, ByteString should stay cached.
|
||||
assertSame(aPrimeByteString, list.getByteString(0)); |
||||
assertSame(bPrimeByteString, list.getByteString(1)); |
||||
} |
||||
} |
@ -0,0 +1,115 @@ |
||||
// 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 protobuf_unittest.UnittestProto; |
||||
|
||||
import junit.framework.TestCase; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Tests to make sure the lazy conversion of UTF8-encoded byte arrays to |
||||
* strings works correctly. |
||||
* |
||||
* @author jonp@google.com (Jon Perlow) |
||||
*/ |
||||
public class LazyStringEndToEndTest extends TestCase { |
||||
|
||||
private static ByteString TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8 = |
||||
ByteString.copyFrom(new byte[] { |
||||
114, 4, -1, 0, -1, 0, -30, 2, 4, -1, |
||||
0, -1, 0, -30, 2, 4, -1, 0, -1, 0, }); |
||||
|
||||
/** |
||||
* Tests that an invalid UTF8 string will roundtrip through a parse |
||||
* and serialization. |
||||
*/ |
||||
public void testParseAndSerialize() throws InvalidProtocolBufferException { |
||||
UnittestProto.TestAllTypes tV2 = UnittestProto.TestAllTypes.parseFrom( |
||||
TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8); |
||||
ByteString bytes = tV2.toByteString(); |
||||
assertEquals(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8, bytes); |
||||
|
||||
tV2.getOptionalString(); |
||||
bytes = tV2.toByteString(); |
||||
assertEquals(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8, bytes); |
||||
} |
||||
|
||||
public void testParseAndWrite() throws IOException { |
||||
UnittestProto.TestAllTypes tV2 = UnittestProto.TestAllTypes.parseFrom( |
||||
TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8); |
||||
byte[] sink = new byte[TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8.size()]; |
||||
CodedOutputStream outputStream = CodedOutputStream.newInstance(sink); |
||||
tV2.writeTo(outputStream); |
||||
outputStream.flush(); |
||||
assertEquals( |
||||
TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8, |
||||
ByteString.copyFrom(sink)); |
||||
} |
||||
|
||||
public void testCaching() { |
||||
String a = "a"; |
||||
String b = "b"; |
||||
String c = "c"; |
||||
UnittestProto.TestAllTypes proto = UnittestProto.TestAllTypes.newBuilder() |
||||
.setOptionalString(a) |
||||
.addRepeatedString(b) |
||||
.addRepeatedString(c) |
||||
.build(); |
||||
|
||||
// String should be the one we passed it.
|
||||
assertSame(a, proto.getOptionalString()); |
||||
assertSame(b, proto.getRepeatedString(0)); |
||||
assertSame(c, proto.getRepeatedString(1)); |
||||
|
||||
|
||||
// There's no way to directly observe that the ByteString is cached
|
||||
// correctly on serialization, but we can observe that it had to recompute
|
||||
// the string after serialization.
|
||||
proto.toByteString(); |
||||
String aPrime = proto.getOptionalString(); |
||||
assertNotSame(a, aPrime); |
||||
assertEquals(a, aPrime); |
||||
String bPrime = proto.getRepeatedString(0); |
||||
assertNotSame(b, bPrime); |
||||
assertEquals(b, bPrime); |
||||
String cPrime = proto.getRepeatedString(1); |
||||
assertNotSame(c, cPrime); |
||||
assertEquals(c, cPrime); |
||||
|
||||
// And now the string should stay cached.
|
||||
assertSame(aPrime, proto.getOptionalString()); |
||||
assertSame(bPrime, proto.getRepeatedString(0)); |
||||
assertSame(cPrime, proto.getRepeatedString(1)); |
||||
} |
||||
} |
@ -0,0 +1,185 @@ |
||||
// 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 protobuf_unittest.Vehicle; |
||||
import protobuf_unittest.Wheel; |
||||
|
||||
import junit.framework.TestCase; |
||||
|
||||
import java.util.List; |
||||
import java.util.ArrayList; |
||||
|
||||
/** |
||||
* Test cases that exercise end-to-end use cases involving |
||||
* {@link SingleFieldBuilder} and {@link RepeatedFieldBuilder}. |
||||
* |
||||
* @author jonp@google.com (Jon Perlow) |
||||
*/ |
||||
public class NestedBuildersTest extends TestCase { |
||||
|
||||
public void testMessagesAndBuilders() { |
||||
Vehicle.Builder vehicleBuilder = Vehicle.newBuilder(); |
||||
vehicleBuilder.addWheelBuilder() |
||||
.setRadius(4) |
||||
.setWidth(1); |
||||
vehicleBuilder.addWheelBuilder() |
||||
.setRadius(4) |
||||
.setWidth(2); |
||||
vehicleBuilder.addWheelBuilder() |
||||
.setRadius(4) |
||||
.setWidth(3); |
||||
vehicleBuilder.addWheelBuilder() |
||||
.setRadius(4) |
||||
.setWidth(4); |
||||
vehicleBuilder.getEngineBuilder() |
||||
.setLiters(10); |
||||
|
||||
Vehicle vehicle = vehicleBuilder.build(); |
||||
assertEquals(4, vehicle.getWheelCount()); |
||||
for (int i = 0; i < 4; i++) { |
||||
Wheel wheel = vehicle.getWheel(i); |
||||
assertEquals(4, wheel.getRadius()); |
||||
assertEquals(i + 1, wheel.getWidth()); |
||||
} |
||||
assertEquals(10, vehicle.getEngine().getLiters()); |
||||
|
||||
for (int i = 0; i < 4; i++) { |
||||
vehicleBuilder.getWheelBuilder(i) |
||||
.setRadius(5) |
||||
.setWidth(i + 10); |
||||
} |
||||
vehicleBuilder.getEngineBuilder().setLiters(20); |
||||
|
||||
vehicle = vehicleBuilder.build(); |
||||
for (int i = 0; i < 4; i++) { |
||||
Wheel wheel = vehicle.getWheel(i); |
||||
assertEquals(5, wheel.getRadius()); |
||||
assertEquals(i + 10, wheel.getWidth()); |
||||
} |
||||
assertEquals(20, vehicle.getEngine().getLiters()); |
||||
assertTrue(vehicle.hasEngine()); |
||||
} |
||||
|
||||
public void testMessagesAreCached() { |
||||
Vehicle.Builder vehicleBuilder = Vehicle.newBuilder(); |
||||
vehicleBuilder.addWheelBuilder() |
||||
.setRadius(1) |
||||
.setWidth(2); |
||||
vehicleBuilder.addWheelBuilder() |
||||
.setRadius(3) |
||||
.setWidth(4); |
||||
vehicleBuilder.addWheelBuilder() |
||||
.setRadius(5) |
||||
.setWidth(6); |
||||
vehicleBuilder.addWheelBuilder() |
||||
.setRadius(7) |
||||
.setWidth(8); |
||||
|
||||
// Make sure messages are cached.
|
||||
List<Wheel> wheels = new ArrayList<Wheel>(vehicleBuilder.getWheelList()); |
||||
for (int i = 0; i < wheels.size(); i++) { |
||||
assertSame(wheels.get(i), vehicleBuilder.getWheel(i)); |
||||
} |
||||
|
||||
// Now get builders and check they didn't change.
|
||||
for (int i = 0; i < wheels.size(); i++) { |
||||
vehicleBuilder.getWheel(i); |
||||
} |
||||
for (int i = 0; i < wheels.size(); i++) { |
||||
assertSame(wheels.get(i), vehicleBuilder.getWheel(i)); |
||||
} |
||||
|
||||
// Change just one
|
||||
vehicleBuilder.getWheelBuilder(3) |
||||
.setRadius(20).setWidth(20); |
||||
|
||||
// Now get wheels and check that only that one changed
|
||||
for (int i = 0; i < wheels.size(); i++) { |
||||
if (i < 3) { |
||||
assertSame(wheels.get(i), vehicleBuilder.getWheel(i)); |
||||
} else { |
||||
assertNotSame(wheels.get(i), vehicleBuilder.getWheel(i)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void testRemove_WithNestedBuilders() { |
||||
Vehicle.Builder vehicleBuilder = Vehicle.newBuilder(); |
||||
vehicleBuilder.addWheelBuilder() |
||||
.setRadius(1) |
||||
.setWidth(1); |
||||
vehicleBuilder.addWheelBuilder() |
||||
.setRadius(2) |
||||
.setWidth(2); |
||||
vehicleBuilder.removeWheel(0); |
||||
|
||||
assertEquals(1, vehicleBuilder.getWheelCount()); |
||||
assertEquals(2, vehicleBuilder.getWheel(0).getRadius()); |
||||
} |
||||
|
||||
public void testRemove_WithNestedMessages() { |
||||
Vehicle.Builder vehicleBuilder = Vehicle.newBuilder(); |
||||
vehicleBuilder.addWheel(Wheel.newBuilder() |
||||
.setRadius(1) |
||||
.setWidth(1)); |
||||
vehicleBuilder.addWheel(Wheel.newBuilder() |
||||
.setRadius(2) |
||||
.setWidth(2)); |
||||
vehicleBuilder.removeWheel(0); |
||||
|
||||
assertEquals(1, vehicleBuilder.getWheelCount()); |
||||
assertEquals(2, vehicleBuilder.getWheel(0).getRadius()); |
||||
} |
||||
|
||||
public void testMerge() { |
||||
Vehicle vehicle1 = Vehicle.newBuilder() |
||||
.addWheel(Wheel.newBuilder().setRadius(1).build()) |
||||
.addWheel(Wheel.newBuilder().setRadius(2).build()) |
||||
.build(); |
||||
|
||||
Vehicle vehicle2 = Vehicle.newBuilder() |
||||
.mergeFrom(vehicle1) |
||||
.build(); |
||||
// List should be the same -- no allocation
|
||||
assertSame(vehicle1.getWheelList(), vehicle2.getWheelList()); |
||||
|
||||
Vehicle vehicle3 = vehicle1.toBuilder().build(); |
||||
assertSame(vehicle1.getWheelList(), vehicle3.getWheelList()); |
||||
} |
||||
|
||||
public void testGettingBuilderMarksFieldAsHaving() { |
||||
Vehicle.Builder vehicleBuilder = Vehicle.newBuilder(); |
||||
vehicleBuilder.getEngineBuilder(); |
||||
Vehicle vehicle = vehicleBuilder.buildPartial(); |
||||
assertTrue(vehicle.hasEngine()); |
||||
} |
||||
} |
@ -0,0 +1,190 @@ |
||||
// 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 protobuf_unittest.UnittestProto.TestAllTypes; |
||||
import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder; |
||||
|
||||
import junit.framework.TestCase; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* Tests for {@link RepeatedFieldBuilder}. This tests basic functionality. |
||||
* More extensive testing is provided via other tests that exercise the |
||||
* builder. |
||||
* |
||||
* @author jonp@google.com (Jon Perlow) |
||||
*/ |
||||
public class RepeatedFieldBuilderTest extends TestCase { |
||||
|
||||
public void testBasicUse() { |
||||
TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent(); |
||||
RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder, |
||||
TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent); |
||||
builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build()); |
||||
builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build()); |
||||
assertEquals(0, builder.getMessage(0).getOptionalInt32()); |
||||
assertEquals(1, builder.getMessage(1).getOptionalInt32()); |
||||
|
||||
List<TestAllTypes> list = builder.build(); |
||||
assertEquals(2, list.size()); |
||||
assertEquals(0, list.get(0).getOptionalInt32()); |
||||
assertEquals(1, list.get(1).getOptionalInt32()); |
||||
assertIsUnmodifiable(list); |
||||
|
||||
// Make sure it doesn't change.
|
||||
List<TestAllTypes> list2 = builder.build(); |
||||
assertSame(list, list2); |
||||
assertEquals(0, mockParent.getInvalidationCount()); |
||||
} |
||||
|
||||
public void testGoingBackAndForth() { |
||||
TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent(); |
||||
RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder, |
||||
TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent); |
||||
builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build()); |
||||
builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build()); |
||||
assertEquals(0, builder.getMessage(0).getOptionalInt32()); |
||||
assertEquals(1, builder.getMessage(1).getOptionalInt32()); |
||||
|
||||
// Convert to list
|
||||
List<TestAllTypes> list = builder.build(); |
||||
assertEquals(2, list.size()); |
||||
assertEquals(0, list.get(0).getOptionalInt32()); |
||||
assertEquals(1, list.get(1).getOptionalInt32()); |
||||
assertIsUnmodifiable(list); |
||||
|
||||
// Update 0th item
|
||||
assertEquals(0, mockParent.getInvalidationCount()); |
||||
builder.getBuilder(0).setOptionalString("foo"); |
||||
assertEquals(1, mockParent.getInvalidationCount()); |
||||
list = builder.build(); |
||||
assertEquals(2, list.size()); |
||||
assertEquals(0, list.get(0).getOptionalInt32()); |
||||
assertEquals("foo", list.get(0).getOptionalString()); |
||||
assertEquals(1, list.get(1).getOptionalInt32()); |
||||
assertIsUnmodifiable(list); |
||||
assertEquals(1, mockParent.getInvalidationCount()); |
||||
} |
||||
|
||||
public void testVariousMethods() { |
||||
TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent(); |
||||
RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder, |
||||
TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent); |
||||
builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build()); |
||||
builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(2).build()); |
||||
builder.addBuilder(0, TestAllTypes.getDefaultInstance()) |
||||
.setOptionalInt32(0); |
||||
builder.addBuilder(TestAllTypes.getDefaultInstance()).setOptionalInt32(3); |
||||
|
||||
assertEquals(0, builder.getMessage(0).getOptionalInt32()); |
||||
assertEquals(1, builder.getMessage(1).getOptionalInt32()); |
||||
assertEquals(2, builder.getMessage(2).getOptionalInt32()); |
||||
assertEquals(3, builder.getMessage(3).getOptionalInt32()); |
||||
|
||||
assertEquals(0, mockParent.getInvalidationCount()); |
||||
List<TestAllTypes> messages = builder.build(); |
||||
assertEquals(4, messages.size()); |
||||
assertSame(messages, builder.build()); // expect same list
|
||||
|
||||
// Remove a message.
|
||||
builder.remove(2); |
||||
assertEquals(1, mockParent.getInvalidationCount()); |
||||
assertEquals(3, builder.getCount()); |
||||
assertEquals(0, builder.getMessage(0).getOptionalInt32()); |
||||
assertEquals(1, builder.getMessage(1).getOptionalInt32()); |
||||
assertEquals(3, builder.getMessage(2).getOptionalInt32()); |
||||
|
||||
// Remove a builder.
|
||||
builder.remove(0); |
||||
assertEquals(1, mockParent.getInvalidationCount()); |
||||
assertEquals(2, builder.getCount()); |
||||
assertEquals(1, builder.getMessage(0).getOptionalInt32()); |
||||
assertEquals(3, builder.getMessage(1).getOptionalInt32()); |
||||
|
||||
// Test clear.
|
||||
builder.clear(); |
||||
assertEquals(1, mockParent.getInvalidationCount()); |
||||
assertEquals(0, builder.getCount()); |
||||
assertTrue(builder.isEmpty()); |
||||
} |
||||
|
||||
public void testLists() { |
||||
TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent(); |
||||
RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder, |
||||
TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent); |
||||
builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build()); |
||||
builder.addMessage(0, |
||||
TestAllTypes.newBuilder().setOptionalInt32(0).build()); |
||||
assertEquals(0, builder.getMessage(0).getOptionalInt32()); |
||||
assertEquals(1, builder.getMessage(1).getOptionalInt32()); |
||||
|
||||
// Use list of builders.
|
||||
List<TestAllTypes.Builder> builders = builder.getBuilderList(); |
||||
assertEquals(0, builders.get(0).getOptionalInt32()); |
||||
assertEquals(1, builders.get(1).getOptionalInt32()); |
||||
builders.get(0).setOptionalInt32(10); |
||||
builders.get(1).setOptionalInt32(11); |
||||
|
||||
// Use list of protos
|
||||
List<TestAllTypes> protos = builder.getMessageList(); |
||||
assertEquals(10, protos.get(0).getOptionalInt32()); |
||||
assertEquals(11, protos.get(1).getOptionalInt32()); |
||||
|
||||
// Add an item to the builders and verify it's updated in both
|
||||
builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(12).build()); |
||||
assertEquals(3, builders.size()); |
||||
assertEquals(3, protos.size()); |
||||
} |
||||
|
||||
private void assertIsUnmodifiable(List<?> list) { |
||||
if (list == Collections.emptyList()) { |
||||
// OKAY -- Need to check this b/c EmptyList allows you to call clear.
|
||||
} else { |
||||
try { |
||||
list.clear(); |
||||
fail("List wasn't immutable"); |
||||
} catch (UnsupportedOperationException e) { |
||||
// good
|
||||
} |
||||
} |
||||
} |
||||
|
||||
private RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder, |
||||
TestAllTypesOrBuilder> |
||||
newRepeatedFieldBuilder(GeneratedMessage.BuilderParent parent) { |
||||
return new RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder, |
||||
TestAllTypesOrBuilder>(Collections.<TestAllTypes>emptyList(), false, |
||||
parent, false); |
||||
} |
||||
} |
@ -0,0 +1,155 @@ |
||||
// 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 protobuf_unittest.UnittestProto.TestAllTypes; |
||||
import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder; |
||||
|
||||
import junit.framework.TestCase; |
||||
|
||||
/** |
||||
* Tests for {@link SingleFieldBuilder}. This tests basic functionality. |
||||
* More extensive testing is provided via other tests that exercise the |
||||
* builder. |
||||
* |
||||
* @author jonp@google.com (Jon Perlow) |
||||
*/ |
||||
public class SingleFieldBuilderTest extends TestCase { |
||||
|
||||
public void testBasicUseAndInvalidations() { |
||||
TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent(); |
||||
SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder, |
||||
TestAllTypesOrBuilder> builder = |
||||
new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder, |
||||
TestAllTypesOrBuilder>( |
||||
TestAllTypes.getDefaultInstance(), |
||||
mockParent, |
||||
false); |
||||
assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage()); |
||||
assertEquals(TestAllTypes.getDefaultInstance(), |
||||
builder.getBuilder().buildPartial()); |
||||
assertEquals(0, mockParent.getInvalidationCount()); |
||||
|
||||
builder.getBuilder().setOptionalInt32(10); |
||||
assertEquals(0, mockParent.getInvalidationCount()); |
||||
TestAllTypes message = builder.build(); |
||||
assertEquals(10, message.getOptionalInt32()); |
||||
|
||||
// Test that we receive invalidations now that build has been called.
|
||||
assertEquals(0, mockParent.getInvalidationCount()); |
||||
builder.getBuilder().setOptionalInt32(20); |
||||
assertEquals(1, mockParent.getInvalidationCount()); |
||||
|
||||
// Test that we don't keep getting invalidations on every change
|
||||
builder.getBuilder().setOptionalInt32(30); |
||||
assertEquals(1, mockParent.getInvalidationCount()); |
||||
|
||||
} |
||||
|
||||
public void testSetMessage() { |
||||
TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent(); |
||||
SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder, |
||||
TestAllTypesOrBuilder> builder = |
||||
new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder, |
||||
TestAllTypesOrBuilder>( |
||||
TestAllTypes.getDefaultInstance(), |
||||
mockParent, |
||||
false); |
||||
builder.setMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build()); |
||||
assertEquals(0, builder.getMessage().getOptionalInt32()); |
||||
|
||||
// Update message using the builder
|
||||
builder.getBuilder().setOptionalInt32(1); |
||||
assertEquals(0, mockParent.getInvalidationCount()); |
||||
assertEquals(1, builder.getBuilder().getOptionalInt32()); |
||||
assertEquals(1, builder.getMessage().getOptionalInt32()); |
||||
builder.build(); |
||||
builder.getBuilder().setOptionalInt32(2); |
||||
assertEquals(2, builder.getBuilder().getOptionalInt32()); |
||||
assertEquals(2, builder.getMessage().getOptionalInt32()); |
||||
|
||||
// Make sure message stays cached
|
||||
assertSame(builder.getMessage(), builder.getMessage()); |
||||
} |
||||
|
||||
public void testClear() { |
||||
TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent(); |
||||
SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder, |
||||
TestAllTypesOrBuilder> builder = |
||||
new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder, |
||||
TestAllTypesOrBuilder>( |
||||
TestAllTypes.getDefaultInstance(), |
||||
mockParent, |
||||
false); |
||||
builder.setMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build()); |
||||
assertNotSame(TestAllTypes.getDefaultInstance(), builder.getMessage()); |
||||
builder.clear(); |
||||
assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage()); |
||||
|
||||
builder.getBuilder().setOptionalInt32(1); |
||||
assertNotSame(TestAllTypes.getDefaultInstance(), builder.getMessage()); |
||||
builder.clear(); |
||||
assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage()); |
||||
} |
||||
|
||||
public void testMerge() { |
||||
TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent(); |
||||
SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder, |
||||
TestAllTypesOrBuilder> builder = |
||||
new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder, |
||||
TestAllTypesOrBuilder>( |
||||
TestAllTypes.getDefaultInstance(), |
||||
mockParent, |
||||
false); |
||||
|
||||
// Merge into default field.
|
||||
builder.mergeFrom(TestAllTypes.getDefaultInstance()); |
||||
assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage()); |
||||
|
||||
// Merge into non-default field on existing builder.
|
||||
builder.getBuilder().setOptionalInt32(2); |
||||
builder.mergeFrom(TestAllTypes.newBuilder() |
||||
.setOptionalDouble(4.0) |
||||
.buildPartial()); |
||||
assertEquals(2, builder.getMessage().getOptionalInt32()); |
||||
assertEquals(4.0, builder.getMessage().getOptionalDouble()); |
||||
|
||||
// Merge into non-default field on existing message
|
||||
builder.setMessage(TestAllTypes.newBuilder() |
||||
.setOptionalInt32(10) |
||||
.buildPartial()); |
||||
builder.mergeFrom(TestAllTypes.newBuilder() |
||||
.setOptionalDouble(5.0) |
||||
.buildPartial()); |
||||
assertEquals(10, builder.getMessage().getOptionalInt32()); |
||||
assertEquals(5.0, builder.getMessage().getOptionalDouble()); |
||||
} |
||||
} |
@ -0,0 +1,378 @@ |
||||
// 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 junit.framework.TestCase; |
||||
|
||||
import java.util.AbstractMap.SimpleEntry; |
||||
import java.util.ArrayList; |
||||
import java.util.Arrays; |
||||
import java.util.HashMap; |
||||
import java.util.Iterator; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
import java.util.TreeSet; |
||||
|
||||
/** |
||||
* @author darick@google.com Darick Tong |
||||
*/ |
||||
public class SmallSortedMapTest extends TestCase { |
||||
|
||||
public void testPutAndGetArrayEntriesOnly() { |
||||
runPutAndGetTest(3); |
||||
} |
||||
|
||||
public void testPutAndGetOverflowEntries() { |
||||
runPutAndGetTest(6); |
||||
} |
||||
|
||||
private void runPutAndGetTest(int numElements) { |
||||
// Test with even and odd arraySize
|
||||
SmallSortedMap<Integer, Integer> map1 = |
||||
SmallSortedMap.newInstanceForTest(3); |
||||
SmallSortedMap<Integer, Integer> map2 = |
||||
SmallSortedMap.newInstanceForTest(4); |
||||
SmallSortedMap<Integer, Integer> map3 = |
||||
SmallSortedMap.newInstanceForTest(3); |
||||
SmallSortedMap<Integer, Integer> map4 = |
||||
SmallSortedMap.newInstanceForTest(4); |
||||
|
||||
// Test with puts in ascending order.
|
||||
for (int i = 0; i < numElements; i++) { |
||||
assertNull(map1.put(i, i + 1)); |
||||
assertNull(map2.put(i, i + 1)); |
||||
} |
||||
// Test with puts in descending order.
|
||||
for (int i = numElements - 1; i >= 0; i--) { |
||||
assertNull(map3.put(i, i + 1)); |
||||
assertNull(map4.put(i, i + 1)); |
||||
} |
||||
|
||||
assertEquals(Math.min(3, numElements), map1.getNumArrayEntries()); |
||||
assertEquals(Math.min(4, numElements), map2.getNumArrayEntries()); |
||||
assertEquals(Math.min(3, numElements), map3.getNumArrayEntries()); |
||||
assertEquals(Math.min(4, numElements), map4.getNumArrayEntries()); |
||||
|
||||
List<SmallSortedMap<Integer, Integer>> allMaps = |
||||
new ArrayList<SmallSortedMap<Integer, Integer>>(); |
||||
allMaps.add(map1); |
||||
allMaps.add(map2); |
||||
allMaps.add(map3); |
||||
allMaps.add(map4); |
||||
|
||||
for (SmallSortedMap<Integer, Integer> map : allMaps) { |
||||
assertEquals(numElements, map.size()); |
||||
for (int i = 0; i < numElements; i++) { |
||||
assertEquals(new Integer(i + 1), map.get(i)); |
||||
} |
||||
} |
||||
|
||||
assertEquals(map1, map2); |
||||
assertEquals(map2, map3); |
||||
assertEquals(map3, map4); |
||||
} |
||||
|
||||
public void testReplacingPut() { |
||||
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); |
||||
for (int i = 0; i < 6; i++) { |
||||
assertNull(map.put(i, i + 1)); |
||||
assertNull(map.remove(i + 1)); |
||||
} |
||||
for (int i = 0; i < 6; i++) { |
||||
assertEquals(new Integer(i + 1), map.put(i, i + 2)); |
||||
} |
||||
} |
||||
|
||||
public void testRemove() { |
||||
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); |
||||
for (int i = 0; i < 6; i++) { |
||||
assertNull(map.put(i, i + 1)); |
||||
assertNull(map.remove(i + 1)); |
||||
} |
||||
|
||||
assertEquals(3, map.getNumArrayEntries()); |
||||
assertEquals(3, map.getNumOverflowEntries()); |
||||
assertEquals(6, map.size()); |
||||
assertEquals(makeSortedKeySet(0, 1, 2, 3, 4, 5), map.keySet()); |
||||
|
||||
assertEquals(new Integer(2), map.remove(1)); |
||||
assertEquals(3, map.getNumArrayEntries()); |
||||
assertEquals(2, map.getNumOverflowEntries()); |
||||
assertEquals(5, map.size()); |
||||
assertEquals(makeSortedKeySet(0, 2, 3, 4, 5), map.keySet()); |
||||
|
||||
assertEquals(new Integer(5), map.remove(4)); |
||||
assertEquals(3, map.getNumArrayEntries()); |
||||
assertEquals(1, map.getNumOverflowEntries()); |
||||
assertEquals(4, map.size()); |
||||
assertEquals(makeSortedKeySet(0, 2, 3, 5), map.keySet()); |
||||
|
||||
assertEquals(new Integer(4), map.remove(3)); |
||||
assertEquals(3, map.getNumArrayEntries()); |
||||
assertEquals(0, map.getNumOverflowEntries()); |
||||
assertEquals(3, map.size()); |
||||
assertEquals(makeSortedKeySet(0, 2, 5), map.keySet()); |
||||
|
||||
assertNull(map.remove(3)); |
||||
assertEquals(3, map.getNumArrayEntries()); |
||||
assertEquals(0, map.getNumOverflowEntries()); |
||||
assertEquals(3, map.size()); |
||||
|
||||
assertEquals(new Integer(1), map.remove(0)); |
||||
assertEquals(2, map.getNumArrayEntries()); |
||||
assertEquals(0, map.getNumOverflowEntries()); |
||||
assertEquals(2, map.size()); |
||||
} |
||||
|
||||
public void testClear() { |
||||
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); |
||||
for (int i = 0; i < 6; i++) { |
||||
assertNull(map.put(i, i + 1)); |
||||
} |
||||
map.clear(); |
||||
assertEquals(0, map.getNumArrayEntries()); |
||||
assertEquals(0, map.getNumOverflowEntries()); |
||||
assertEquals(0, map.size()); |
||||
} |
||||
|
||||
public void testGetArrayEntryAndOverflowEntries() { |
||||
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); |
||||
for (int i = 0; i < 6; i++) { |
||||
assertNull(map.put(i, i + 1)); |
||||
} |
||||
assertEquals(3, map.getNumArrayEntries()); |
||||
for (int i = 0; i < 3; i++) { |
||||
Map.Entry<Integer, Integer> entry = map.getArrayEntryAt(i); |
||||
assertEquals(new Integer(i), entry.getKey()); |
||||
assertEquals(new Integer(i + 1), entry.getValue()); |
||||
} |
||||
Iterator<Map.Entry<Integer, Integer>> it = |
||||
map.getOverflowEntries().iterator(); |
||||
for (int i = 3; i < 6; i++) { |
||||
assertTrue(it.hasNext()); |
||||
Map.Entry<Integer, Integer> entry = it.next(); |
||||
assertEquals(new Integer(i), entry.getKey()); |
||||
assertEquals(new Integer(i + 1), entry.getValue()); |
||||
} |
||||
assertFalse(it.hasNext()); |
||||
} |
||||
|
||||
public void testEntrySetContains() { |
||||
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); |
||||
for (int i = 0; i < 6; i++) { |
||||
assertNull(map.put(i, i + 1)); |
||||
} |
||||
Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet(); |
||||
for (int i = 0; i < 6; i++) { |
||||
assertTrue( |
||||
entrySet.contains(new SimpleEntry<Integer, Integer>(i, i + 1))); |
||||
assertFalse( |
||||
entrySet.contains(new SimpleEntry<Integer, Integer>(i, i))); |
||||
} |
||||
} |
||||
|
||||
public void testEntrySetAdd() { |
||||
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); |
||||
Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet(); |
||||
for (int i = 0; i < 6; i++) { |
||||
Map.Entry<Integer, Integer> entry = |
||||
new SimpleEntry<Integer, Integer>(i, i + 1); |
||||
assertTrue(entrySet.add(entry)); |
||||
assertFalse(entrySet.add(entry)); |
||||
} |
||||
for (int i = 0; i < 6; i++) { |
||||
assertEquals(new Integer(i + 1), map.get(i)); |
||||
} |
||||
assertEquals(3, map.getNumArrayEntries()); |
||||
assertEquals(3, map.getNumOverflowEntries()); |
||||
assertEquals(6, map.size()); |
||||
} |
||||
|
||||
public void testEntrySetRemove() { |
||||
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); |
||||
Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet(); |
||||
for (int i = 0; i < 6; i++) { |
||||
assertNull(map.put(i, i + 1)); |
||||
} |
||||
for (int i = 0; i < 6; i++) { |
||||
Map.Entry<Integer, Integer> entry = |
||||
new SimpleEntry<Integer, Integer>(i, i + 1); |
||||
assertTrue(entrySet.remove(entry)); |
||||
assertFalse(entrySet.remove(entry)); |
||||
} |
||||
assertTrue(map.isEmpty()); |
||||
assertEquals(0, map.getNumArrayEntries()); |
||||
assertEquals(0, map.getNumOverflowEntries()); |
||||
assertEquals(0, map.size()); |
||||
} |
||||
|
||||
public void testEntrySetClear() { |
||||
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); |
||||
for (int i = 0; i < 6; i++) { |
||||
assertNull(map.put(i, i + 1)); |
||||
} |
||||
map.entrySet().clear(); |
||||
assertTrue(map.isEmpty()); |
||||
assertEquals(0, map.getNumArrayEntries()); |
||||
assertEquals(0, map.getNumOverflowEntries()); |
||||
assertEquals(0, map.size()); |
||||
} |
||||
|
||||
public void testEntrySetIteratorNext() { |
||||
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); |
||||
for (int i = 0; i < 6; i++) { |
||||
assertNull(map.put(i, i + 1)); |
||||
} |
||||
Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator(); |
||||
for (int i = 0; i < 6; i++) { |
||||
assertTrue(it.hasNext()); |
||||
Map.Entry<Integer, Integer> entry = it.next(); |
||||
assertEquals(new Integer(i), entry.getKey()); |
||||
assertEquals(new Integer(i + 1), entry.getValue()); |
||||
} |
||||
assertFalse(it.hasNext()); |
||||
} |
||||
|
||||
public void testEntrySetIteratorRemove() { |
||||
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); |
||||
for (int i = 0; i < 6; i++) { |
||||
assertNull(map.put(i, i + 1)); |
||||
} |
||||
Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator(); |
||||
for (int i = 0; i < 6; i++) { |
||||
assertTrue(map.containsKey(i)); |
||||
it.next(); |
||||
it.remove(); |
||||
assertFalse(map.containsKey(i)); |
||||
assertEquals(6 - i - 1, map.size()); |
||||
} |
||||
} |
||||
|
||||
public void testMapEntryModification() { |
||||
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); |
||||
for (int i = 0; i < 6; i++) { |
||||
assertNull(map.put(i, i + 1)); |
||||
} |
||||
Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator(); |
||||
for (int i = 0; i < 6; i++) { |
||||
Map.Entry<Integer, Integer> entry = it.next(); |
||||
entry.setValue(i + 23); |
||||
} |
||||
for (int i = 0; i < 6; i++) { |
||||
assertEquals(new Integer(i + 23), map.get(i)); |
||||
} |
||||
} |
||||
|
||||
public void testMakeImmutable() { |
||||
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3); |
||||
for (int i = 0; i < 6; i++) { |
||||
assertNull(map.put(i, i + 1)); |
||||
} |
||||
map.makeImmutable(); |
||||
assertEquals(new Integer(1), map.get(0)); |
||||
assertEquals(6, map.size()); |
||||
|
||||
try { |
||||
map.put(23, 23); |
||||
fail("Expected UnsupportedOperationException"); |
||||
} catch (UnsupportedOperationException expected) { |
||||
} |
||||
|
||||
Map<Integer, Integer> other = new HashMap<Integer, Integer>(); |
||||
other.put(23, 23); |
||||
try { |
||||
map.putAll(other); |
||||
fail("Expected UnsupportedOperationException"); |
||||
} catch (UnsupportedOperationException expected) { |
||||
} |
||||
|
||||
try { |
||||
map.remove(0); |
||||
fail("Expected UnsupportedOperationException"); |
||||
} catch (UnsupportedOperationException expected) { |
||||
} |
||||
|
||||
try { |
||||
map.clear(); |
||||
fail("Expected UnsupportedOperationException"); |
||||
} catch (UnsupportedOperationException expected) { |
||||
} |
||||
|
||||
Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet(); |
||||
try { |
||||
entrySet.clear(); |
||||
fail("Expected UnsupportedOperationException"); |
||||
} catch (UnsupportedOperationException expected) { |
||||
} |
||||
|
||||
Iterator<Map.Entry<Integer, Integer>> it = entrySet.iterator(); |
||||
while (it.hasNext()) { |
||||
Map.Entry<Integer, Integer> entry = it.next(); |
||||
try { |
||||
entry.setValue(0); |
||||
fail("Expected UnsupportedOperationException"); |
||||
} catch (UnsupportedOperationException expected) { |
||||
} |
||||
try { |
||||
it.remove(); |
||||
fail("Expected UnsupportedOperationException"); |
||||
} catch (UnsupportedOperationException expected) { |
||||
} |
||||
} |
||||
|
||||
Set<Integer> keySet = map.keySet(); |
||||
try { |
||||
keySet.clear(); |
||||
fail("Expected UnsupportedOperationException"); |
||||
} catch (UnsupportedOperationException expected) { |
||||
} |
||||
|
||||
Iterator<Integer> keys = keySet.iterator(); |
||||
while (keys.hasNext()) { |
||||
Integer key = keys.next(); |
||||
try { |
||||
keySet.remove(key); |
||||
fail("Expected UnsupportedOperationException"); |
||||
} catch (UnsupportedOperationException expected) { |
||||
} |
||||
try { |
||||
keys.remove(); |
||||
fail("Expected UnsupportedOperationException"); |
||||
} catch (UnsupportedOperationException expected) { |
||||
} |
||||
} |
||||
} |
||||
|
||||
private Set<Integer> makeSortedKeySet(Integer... keys) { |
||||
return new TreeSet<Integer>(Arrays.<Integer>asList(keys)); |
||||
} |
||||
} |
@ -0,0 +1,49 @@ |
||||
// 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 junit.framework.TestCase; |
||||
|
||||
/** |
||||
* Tests that proto2 api generation doesn't cause compile errors when |
||||
* compiling protocol buffers that have names that would otherwise conflict |
||||
* if not fully qualified (like @Deprecated and @Override). |
||||
* |
||||
* @author jonp@google.com (Jon Perlow) |
||||
*/ |
||||
public class TestBadIdentifiers extends TestCase { |
||||
|
||||
public void testCompilation() { |
||||
// If this compiles, it means the generation was correct.
|
||||
TestBadIdentifiersProto.Deprecated.newBuilder(); |
||||
TestBadIdentifiersProto.Override.newBuilder(); |
||||
} |
||||
} |
@ -0,0 +1,152 @@ |
||||
// 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 junit.framework.TestCase; |
||||
|
||||
import java.util.Iterator; |
||||
import java.util.ListIterator; |
||||
|
||||
/** |
||||
* Tests for {@link UnmodifiableLazyStringList}. |
||||
* |
||||
* @author jonp@google.com (Jon Perlow) |
||||
*/ |
||||
public class UnmodifiableLazyStringListTest extends TestCase { |
||||
|
||||
private static String STRING_A = "A"; |
||||
private static String STRING_B = "B"; |
||||
private static String STRING_C = "C"; |
||||
|
||||
private static ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A"); |
||||
private static ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B"); |
||||
private static ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C"); |
||||
|
||||
public void testReadOnlyMethods() { |
||||
LazyStringArrayList rawList = createSampleList(); |
||||
UnmodifiableLazyStringList list = new UnmodifiableLazyStringList(rawList); |
||||
assertEquals(3, list.size()); |
||||
assertSame(STRING_A, list.get(0)); |
||||
assertSame(STRING_B, list.get(1)); |
||||
assertSame(STRING_C, list.get(2)); |
||||
assertEquals(BYTE_STRING_A, list.getByteString(0)); |
||||
assertEquals(BYTE_STRING_B, list.getByteString(1)); |
||||
assertEquals(BYTE_STRING_C, list.getByteString(2)); |
||||
} |
||||
|
||||
public void testModifyMethods() { |
||||
LazyStringArrayList rawList = createSampleList(); |
||||
UnmodifiableLazyStringList list = new UnmodifiableLazyStringList(rawList); |
||||
|
||||
try { |
||||
list.remove(0); |
||||
fail(); |
||||
} catch (UnsupportedOperationException e) { |
||||
// expected
|
||||
} |
||||
assertEquals(3, list.size()); |
||||
|
||||
try { |
||||
list.add(STRING_B); |
||||
fail(); |
||||
} catch (UnsupportedOperationException e) { |
||||
// expected
|
||||
} |
||||
assertEquals(3, list.size()); |
||||
|
||||
try { |
||||
list.set(1, STRING_B); |
||||
fail(); |
||||
} catch (UnsupportedOperationException e) { |
||||
// expected
|
||||
} |
||||
} |
||||
|
||||
public void testIterator() { |
||||
LazyStringArrayList rawList = createSampleList(); |
||||
UnmodifiableLazyStringList list = new UnmodifiableLazyStringList(rawList); |
||||
|
||||
Iterator<String> iter = list.iterator(); |
||||
int count = 0; |
||||
while (iter.hasNext()) { |
||||
iter.next(); |
||||
count++; |
||||
try { |
||||
iter.remove(); |
||||
fail(); |
||||
} catch (UnsupportedOperationException e) { |
||||
// expected
|
||||
} |
||||
} |
||||
assertEquals(3, count); |
||||
|
||||
} |
||||
|
||||
public void testListIterator() { |
||||
LazyStringArrayList rawList = createSampleList(); |
||||
UnmodifiableLazyStringList list = new UnmodifiableLazyStringList(rawList); |
||||
|
||||
ListIterator<String> iter = list.listIterator(); |
||||
int count = 0; |
||||
while (iter.hasNext()) { |
||||
iter.next(); |
||||
count++; |
||||
try { |
||||
iter.remove(); |
||||
fail(); |
||||
} catch (UnsupportedOperationException e) { |
||||
// expected
|
||||
} |
||||
try { |
||||
iter.set("bar"); |
||||
fail(); |
||||
} catch (UnsupportedOperationException e) { |
||||
// expected
|
||||
} |
||||
try { |
||||
iter.add("bar"); |
||||
fail(); |
||||
} catch (UnsupportedOperationException e) { |
||||
// expected
|
||||
} |
||||
} |
||||
assertEquals(3, count); |
||||
|
||||
} |
||||
|
||||
private LazyStringArrayList createSampleList() { |
||||
LazyStringArrayList rawList = new LazyStringArrayList(); |
||||
rawList.add(STRING_A); |
||||
rawList.add(STRING_B); |
||||
rawList.add(STRING_C); |
||||
return rawList; |
||||
} |
||||
} |
@ -0,0 +1,53 @@ |
||||
// 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. |
||||
|
||||
// Author: jonp@google.com (Jon Perlow) |
||||
// |
||||
|
||||
package protobuf_unittest; |
||||
|
||||
option java_multiple_files = true; |
||||
option java_outer_classname = "NestedBuilders"; |
||||
|
||||
|
||||
message Vehicle { |
||||
optional Engine engine = 1; |
||||
repeated Wheel wheel = 2; |
||||
} |
||||
|
||||
message Engine { |
||||
optional int32 cylinder = 1; |
||||
optional int32 liters = 2; |
||||
} |
||||
|
||||
message Wheel { |
||||
optional int32 radius = 1; |
||||
optional int32 width = 2; |
||||
} |
@ -0,0 +1,45 @@ |
||||
// 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. |
||||
|
||||
// Author: Darick Tong (darick@google.com) |
||||
// |
||||
// A proto file with nested extensions. Note that this must be defined in |
||||
// a separate file to properly test the initialization of the outer class. |
||||
|
||||
|
||||
import "com/google/protobuf/non_nested_extension.proto"; |
||||
|
||||
package protobuf_unittest; |
||||
|
||||
message MyNestedExtension { |
||||
extend MessageToBeExtended { |
||||
optional MessageToBeExtended recursiveExtension = 2; |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
// 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. |
||||
|
||||
// Author: Darick Tong (darick@google.com) |
||||
// |
||||
// A proto file with nested extensions for a MessageLite messages. Note that |
||||
// this must be defined in a separate file to properly test the initialization |
||||
// of the outer class. |
||||
|
||||
|
||||
package protobuf_unittest; |
||||
|
||||
option optimize_for = LITE_RUNTIME; |
||||
|
||||
import "com/google/protobuf/non_nested_extension_lite.proto"; |
||||
|
||||
message MyNestedExtensionLite { |
||||
extend MessageLiteToBeExtended { |
||||
optional MessageLiteToBeExtended recursiveExtensionLite = 3; |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
// 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. |
||||
|
||||
// Author: Darick Tong (darick@google.com) |
||||
// |
||||
// A proto file with extensions. |
||||
|
||||
|
||||
package protobuf_unittest; |
||||
|
||||
message MessageToBeExtended { |
||||
extensions 1 to max; |
||||
} |
||||
|
||||
message MyNonNestedExtension { |
||||
} |
||||
|
||||
extend MessageToBeExtended { |
||||
optional MyNonNestedExtension nonNestedExtension = 1; |
||||
} |
||||
|
@ -0,0 +1,50 @@ |
||||
// 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. |
||||
|
||||
// Author: Darick Tong (darick@google.com) |
||||
// |
||||
// A proto file with extensions for a MessageLite messages. |
||||
|
||||
|
||||
package protobuf_unittest; |
||||
|
||||
option optimize_for = LITE_RUNTIME; |
||||
|
||||
message MessageLiteToBeExtended { |
||||
extensions 1 to max; |
||||
} |
||||
|
||||
message MyNonNestedExtensionLite { |
||||
} |
||||
|
||||
extend MessageLiteToBeExtended { |
||||
optional MyNonNestedExtensionLite nonNestedExtensionLite = 1; |
||||
} |
||||
|
@ -0,0 +1,66 @@ |
||||
// 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. |
||||
|
||||
// Author: jonp@google.com (Jon Perlow) |
||||
|
||||
// This file tests that various identifiers work as field and type names even |
||||
// though the same identifiers are used internally by the java code generator. |
||||
|
||||
|
||||
// Some generic_services option(s) added automatically. |
||||
// See: http://go/proto2-generic-services-default |
||||
option java_generic_services = true; // auto-added |
||||
|
||||
package io_protocol_tests; |
||||
|
||||
option java_package = "com.google.protobuf"; |
||||
option java_outer_classname = "TestBadIdentifiersProto"; |
||||
|
||||
message TestMessage { |
||||
} |
||||
|
||||
message Deprecated { |
||||
enum TestEnum { |
||||
FOO = 1; |
||||
} |
||||
|
||||
optional int32 field1 = 1 [deprecated=true]; |
||||
optional TestEnum field2 = 2 [deprecated=true]; |
||||
optional TestMessage field3 = 3 [deprecated=true]; |
||||
} |
||||
|
||||
message Override { |
||||
optional int32 override = 1; |
||||
} |
||||
|
||||
service TestConflictingMethodNames { |
||||
rpc Override(TestMessage) returns (TestMessage); |
||||
} |
||||
|
@ -0,0 +1,64 @@ |
||||
# 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. |
||||
|
||||
""" |
||||
This module is the central entity that determines which implementation of the |
||||
API is used. |
||||
""" |
||||
|
||||
__author__ = 'petar@google.com (Petar Petrov)' |
||||
|
||||
import os |
||||
# This environment variable can be used to switch to a certain implementation |
||||
# of the Python API. Right now only 'python' and 'cpp' are valid values. Any |
||||
# other value will be ignored. |
||||
_implementation_type = os.getenv('PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION', |
||||
'python') |
||||
|
||||
|
||||
if _implementation_type != 'python': |
||||
# For now, by default use the pure-Python implementation. |
||||
# The code below checks if the C extension is available and |
||||
# uses it if it is available. |
||||
_implementation_type = 'cpp' |
||||
## Determine automatically which implementation to use. |
||||
#try: |
||||
# from google.protobuf.internal import cpp_message |
||||
# _implementation_type = 'cpp' |
||||
#except ImportError, e: |
||||
# _implementation_type = 'python' |
||||
|
||||
|
||||
# Usage of this function is discouraged. Clients shouldn't care which |
||||
# implementation of the API is in use. Note that there is no guarantee |
||||
# that differences between APIs will be maintained. |
||||
# Please don't use this function if possible. |
||||
def Type(): |
||||
return _implementation_type |
@ -0,0 +1,616 @@ |
||||
# 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. |
||||
|
||||
"""Contains helper functions used to create protocol message classes from |
||||
Descriptor objects at runtime backed by the protocol buffer C++ API. |
||||
""" |
||||
|
||||
__author__ = 'petar@google.com (Petar Petrov)' |
||||
|
||||
import operator |
||||
from google.protobuf.internal import _net_proto2___python |
||||
from google.protobuf import message |
||||
|
||||
|
||||
_LABEL_REPEATED = _net_proto2___python.LABEL_REPEATED |
||||
_LABEL_OPTIONAL = _net_proto2___python.LABEL_OPTIONAL |
||||
_CPPTYPE_MESSAGE = _net_proto2___python.CPPTYPE_MESSAGE |
||||
_TYPE_MESSAGE = _net_proto2___python.TYPE_MESSAGE |
||||
|
||||
|
||||
def GetDescriptorPool(): |
||||
"""Creates a new DescriptorPool C++ object.""" |
||||
return _net_proto2___python.NewCDescriptorPool() |
||||
|
||||
|
||||
_pool = GetDescriptorPool() |
||||
|
||||
|
||||
def GetFieldDescriptor(full_field_name): |
||||
"""Searches for a field descriptor given a full field name.""" |
||||
return _pool.FindFieldByName(full_field_name) |
||||
|
||||
|
||||
def BuildFile(content): |
||||
"""Registers a new proto file in the underlying C++ descriptor pool.""" |
||||
_net_proto2___python.BuildFile(content) |
||||
|
||||
|
||||
def GetExtensionDescriptor(full_extension_name): |
||||
"""Searches for extension descriptor given a full field name.""" |
||||
return _pool.FindExtensionByName(full_extension_name) |
||||
|
||||
|
||||
def NewCMessage(full_message_name): |
||||
"""Creates a new C++ protocol message by its name.""" |
||||
return _net_proto2___python.NewCMessage(full_message_name) |
||||
|
||||
|
||||
def ScalarProperty(cdescriptor): |
||||
"""Returns a scalar property for the given descriptor.""" |
||||
|
||||
def Getter(self): |
||||
return self._cmsg.GetScalar(cdescriptor) |
||||
|
||||
def Setter(self, value): |
||||
self._cmsg.SetScalar(cdescriptor, value) |
||||
|
||||
return property(Getter, Setter) |
||||
|
||||
|
||||
def CompositeProperty(cdescriptor, message_type): |
||||
"""Returns a Python property the given composite field.""" |
||||
|
||||
def Getter(self): |
||||
sub_message = self._composite_fields.get(cdescriptor.name, None) |
||||
if sub_message is None: |
||||
cmessage = self._cmsg.NewSubMessage(cdescriptor) |
||||
sub_message = message_type._concrete_class(__cmessage=cmessage) |
||||
self._composite_fields[cdescriptor.name] = sub_message |
||||
return sub_message |
||||
|
||||
return property(Getter) |
||||
|
||||
|
||||
class RepeatedScalarContainer(object): |
||||
"""Container for repeated scalar fields.""" |
||||
|
||||
__slots__ = ['_message', '_cfield_descriptor', '_cmsg'] |
||||
|
||||
def __init__(self, msg, cfield_descriptor): |
||||
self._message = msg |
||||
self._cmsg = msg._cmsg |
||||
self._cfield_descriptor = cfield_descriptor |
||||
|
||||
def append(self, value): |
||||
self._cmsg.AddRepeatedScalar( |
||||
self._cfield_descriptor, value) |
||||
|
||||
def extend(self, sequence): |
||||
for element in sequence: |
||||
self.append(element) |
||||
|
||||
def insert(self, key, value): |
||||
values = self[slice(None, None, None)] |
||||
values.insert(key, value) |
||||
self._cmsg.AssignRepeatedScalar(self._cfield_descriptor, values) |
||||
|
||||
def remove(self, value): |
||||
values = self[slice(None, None, None)] |
||||
values.remove(value) |
||||
self._cmsg.AssignRepeatedScalar(self._cfield_descriptor, values) |
||||
|
||||
def __setitem__(self, key, value): |
||||
values = self[slice(None, None, None)] |
||||
values[key] = value |
||||
self._cmsg.AssignRepeatedScalar(self._cfield_descriptor, values) |
||||
|
||||
def __getitem__(self, key): |
||||
return self._cmsg.GetRepeatedScalar(self._cfield_descriptor, key) |
||||
|
||||
def __delitem__(self, key): |
||||
self._cmsg.DeleteRepeatedField(self._cfield_descriptor, key) |
||||
|
||||
def __len__(self): |
||||
return len(self[slice(None, None, None)]) |
||||
|
||||
def __eq__(self, other): |
||||
if self is other: |
||||
return True |
||||
if not operator.isSequenceType(other): |
||||
raise TypeError( |
||||
'Can only compare repeated scalar fields against sequences.') |
||||
# We are presumably comparing against some other sequence type. |
||||
return other == self[slice(None, None, None)] |
||||
|
||||
def __ne__(self, other): |
||||
return not self == other |
||||
|
||||
def __hash__(self): |
||||
raise TypeError('unhashable object') |
||||
|
||||
def sort(self, sort_function=cmp): |
||||
values = self[slice(None, None, None)] |
||||
values.sort(sort_function) |
||||
self._cmsg.AssignRepeatedScalar(self._cfield_descriptor, values) |
||||
|
||||
|
||||
def RepeatedScalarProperty(cdescriptor): |
||||
"""Returns a Python property the given repeated scalar field.""" |
||||
|
||||
def Getter(self): |
||||
container = self._composite_fields.get(cdescriptor.name, None) |
||||
if container is None: |
||||
container = RepeatedScalarContainer(self, cdescriptor) |
||||
self._composite_fields[cdescriptor.name] = container |
||||
return container |
||||
|
||||
def Setter(self, new_value): |
||||
raise AttributeError('Assignment not allowed to repeated field ' |
||||
'"%s" in protocol message object.' % cdescriptor.name) |
||||
|
||||
doc = 'Magic attribute generated for "%s" proto field.' % cdescriptor.name |
||||
return property(Getter, Setter, doc=doc) |
||||
|
||||
|
||||
class RepeatedCompositeContainer(object): |
||||
"""Container for repeated composite fields.""" |
||||
|
||||
__slots__ = ['_message', '_subclass', '_cfield_descriptor', '_cmsg'] |
||||
|
||||
def __init__(self, msg, cfield_descriptor, subclass): |
||||
self._message = msg |
||||
self._cmsg = msg._cmsg |
||||
self._subclass = subclass |
||||
self._cfield_descriptor = cfield_descriptor |
||||
|
||||
def add(self, **kwargs): |
||||
cmessage = self._cmsg.AddMessage(self._cfield_descriptor) |
||||
return self._subclass(__cmessage=cmessage, __owner=self._message, **kwargs) |
||||
|
||||
def extend(self, elem_seq): |
||||
"""Extends by appending the given sequence of elements of the same type |
||||
as this one, copying each individual message. |
||||
""" |
||||
for message in elem_seq: |
||||
self.add().MergeFrom(message) |
||||
|
||||
def MergeFrom(self, other): |
||||
for message in other[:]: |
||||
self.add().MergeFrom(message) |
||||
|
||||
def __getitem__(self, key): |
||||
cmessages = self._cmsg.GetRepeatedMessage( |
||||
self._cfield_descriptor, key) |
||||
subclass = self._subclass |
||||
if not isinstance(cmessages, list): |
||||
return subclass(__cmessage=cmessages, __owner=self._message) |
||||
|
||||
return [subclass(__cmessage=m, __owner=self._message) for m in cmessages] |
||||
|
||||
def __delitem__(self, key): |
||||
self._cmsg.DeleteRepeatedField( |
||||
self._cfield_descriptor, key) |
||||
|
||||
def __len__(self): |
||||
return self._cmsg.FieldLength(self._cfield_descriptor) |
||||
|
||||
def __eq__(self, other): |
||||
"""Compares the current instance with another one.""" |
||||
if self is other: |
||||
return True |
||||
if not isinstance(other, self.__class__): |
||||
raise TypeError('Can only compare repeated composite fields against ' |
||||
'other repeated composite fields.') |
||||
messages = self[slice(None, None, None)] |
||||
other_messages = other[slice(None, None, None)] |
||||
return messages == other_messages |
||||
|
||||
def __hash__(self): |
||||
raise TypeError('unhashable object') |
||||
|
||||
def sort(self, sort_function=cmp): |
||||
messages = [] |
||||
for index in range(len(self)): |
||||
# messages[i][0] is where the i-th element of the new array has to come |
||||
# from. |
||||
# messages[i][1] is where the i-th element of the old array has to go. |
||||
messages.append([index, 0, self[index]]) |
||||
messages.sort(lambda x,y: sort_function(x[2], y[2])) |
||||
|
||||
# Remember which position each elements has to move to. |
||||
for i in range(len(messages)): |
||||
messages[messages[i][0]][1] = i |
||||
|
||||
# Apply the transposition. |
||||
for i in range(len(messages)): |
||||
from_position = messages[i][0] |
||||
if i == from_position: |
||||
continue |
||||
self._cmsg.SwapRepeatedFieldElements( |
||||
self._cfield_descriptor, i, from_position) |
||||
messages[messages[i][1]][0] = from_position |
||||
|
||||
|
||||
def RepeatedCompositeProperty(cdescriptor, message_type): |
||||
"""Returns a Python property for the given repeated composite field.""" |
||||
|
||||
def Getter(self): |
||||
container = self._composite_fields.get(cdescriptor.name, None) |
||||
if container is None: |
||||
container = RepeatedCompositeContainer( |
||||
self, cdescriptor, message_type._concrete_class) |
||||
self._composite_fields[cdescriptor.name] = container |
||||
return container |
||||
|
||||
def Setter(self, new_value): |
||||
raise AttributeError('Assignment not allowed to repeated field ' |
||||
'"%s" in protocol message object.' % cdescriptor.name) |
||||
|
||||
doc = 'Magic attribute generated for "%s" proto field.' % cdescriptor.name |
||||
return property(Getter, Setter, doc=doc) |
||||
|
||||
|
||||
class ExtensionDict(object): |
||||
"""Extension dictionary added to each protocol message.""" |
||||
|
||||
def __init__(self, msg): |
||||
self._message = msg |
||||
self._cmsg = msg._cmsg |
||||
self._values = {} |
||||
|
||||
def __setitem__(self, extension, value): |
||||
from google.protobuf import descriptor |
||||
if not isinstance(extension, descriptor.FieldDescriptor): |
||||
raise KeyError('Bad extension %r.' % (extension,)) |
||||
cdescriptor = extension._cdescriptor |
||||
if (cdescriptor.label != _LABEL_OPTIONAL or |
||||
cdescriptor.cpp_type == _CPPTYPE_MESSAGE): |
||||
raise TypeError('Extension %r is repeated and/or a composite type.' % ( |
||||
extension.full_name,)) |
||||
self._cmsg.SetScalar(cdescriptor, value) |
||||
self._values[extension] = value |
||||
|
||||
def __getitem__(self, extension): |
||||
from google.protobuf import descriptor |
||||
if not isinstance(extension, descriptor.FieldDescriptor): |
||||
raise KeyError('Bad extension %r.' % (extension,)) |
||||
|
||||
cdescriptor = extension._cdescriptor |
||||
if (cdescriptor.label != _LABEL_REPEATED and |
||||
cdescriptor.cpp_type != _CPPTYPE_MESSAGE): |
||||
return self._cmsg.GetScalar(cdescriptor) |
||||
|
||||
ext = self._values.get(extension, None) |
||||
if ext is not None: |
||||
return ext |
||||
|
||||
ext = self._CreateNewHandle(extension) |
||||
self._values[extension] = ext |
||||
return ext |
||||
|
||||
def ClearExtension(self, extension): |
||||
from google.protobuf import descriptor |
||||
if not isinstance(extension, descriptor.FieldDescriptor): |
||||
raise KeyError('Bad extension %r.' % (extension,)) |
||||
self._cmsg.ClearFieldByDescriptor(extension._cdescriptor) |
||||
if extension in self._values: |
||||
del self._values[extension] |
||||
|
||||
def HasExtension(self, extension): |
||||
from google.protobuf import descriptor |
||||
if not isinstance(extension, descriptor.FieldDescriptor): |
||||
raise KeyError('Bad extension %r.' % (extension,)) |
||||
return self._cmsg.HasFieldByDescriptor(extension._cdescriptor) |
||||
|
||||
def _FindExtensionByName(self, name): |
||||
"""Tries to find a known extension with the specified name. |
||||
|
||||
Args: |
||||
name: Extension full name. |
||||
|
||||
Returns: |
||||
Extension field descriptor. |
||||
""" |
||||
return self._message._extensions_by_name.get(name, None) |
||||
|
||||
def _CreateNewHandle(self, extension): |
||||
cdescriptor = extension._cdescriptor |
||||
if (cdescriptor.label != _LABEL_REPEATED and |
||||
cdescriptor.cpp_type == _CPPTYPE_MESSAGE): |
||||
cmessage = self._cmsg.NewSubMessage(cdescriptor) |
||||
return extension.message_type._concrete_class(__cmessage=cmessage) |
||||
|
||||
if cdescriptor.label == _LABEL_REPEATED: |
||||
if cdescriptor.cpp_type == _CPPTYPE_MESSAGE: |
||||
return RepeatedCompositeContainer( |
||||
self._message, cdescriptor, extension.message_type._concrete_class) |
||||
else: |
||||
return RepeatedScalarContainer(self._message, cdescriptor) |
||||
# This shouldn't happen! |
||||
assert False |
||||
return None |
||||
|
||||
|
||||
def NewMessage(message_descriptor, dictionary): |
||||
"""Creates a new protocol message *class*.""" |
||||
_AddClassAttributesForNestedExtensions(message_descriptor, dictionary) |
||||
_AddEnumValues(message_descriptor, dictionary) |
||||
_AddDescriptors(message_descriptor, dictionary) |
||||
|
||||
|
||||
def InitMessage(message_descriptor, cls): |
||||
"""Constructs a new message instance (called before instance's __init__).""" |
||||
cls._extensions_by_name = {} |
||||
_AddInitMethod(message_descriptor, cls) |
||||
_AddMessageMethods(message_descriptor, cls) |
||||
_AddPropertiesForExtensions(message_descriptor, cls) |
||||
|
||||
|
||||
def _AddDescriptors(message_descriptor, dictionary): |
||||
"""Sets up a new protocol message class dictionary. |
||||
|
||||
Args: |
||||
message_descriptor: A Descriptor instance describing this message type. |
||||
dictionary: Class dictionary to which we'll add a '__slots__' entry. |
||||
""" |
||||
dictionary['__descriptors'] = {} |
||||
for field in message_descriptor.fields: |
||||
dictionary['__descriptors'][field.name] = GetFieldDescriptor( |
||||
field.full_name) |
||||
|
||||
dictionary['__slots__'] = list(dictionary['__descriptors'].iterkeys()) + [ |
||||
'_cmsg', '_owner', '_composite_fields', 'Extensions'] |
||||
|
||||
|
||||
def _AddEnumValues(message_descriptor, dictionary): |
||||
"""Sets class-level attributes for all enum fields defined in this message. |
||||
|
||||
Args: |
||||
message_descriptor: Descriptor object for this message type. |
||||
dictionary: Class dictionary that should be populated. |
||||
""" |
||||
for enum_type in message_descriptor.enum_types: |
||||
for enum_value in enum_type.values: |
||||
dictionary[enum_value.name] = enum_value.number |
||||
|
||||
|
||||
def _AddClassAttributesForNestedExtensions(message_descriptor, dictionary): |
||||
"""Adds class attributes for the nested extensions.""" |
||||
extension_dict = message_descriptor.extensions_by_name |
||||
for extension_name, extension_field in extension_dict.iteritems(): |
||||
assert extension_name not in dictionary |
||||
dictionary[extension_name] = extension_field |
||||
|
||||
|
||||
def _AddInitMethod(message_descriptor, cls): |
||||
"""Adds an __init__ method to cls.""" |
||||
|
||||
# Create and attach message field properties to the message class. |
||||
# This can be done just once per message class, since property setters and |
||||
# getters are passed the message instance. |
||||
# This makes message instantiation extremely fast, and at the same time it |
||||
# doesn't require the creation of property objects for each message instance, |
||||
# which saves a lot of memory. |
||||
for field in message_descriptor.fields: |
||||
field_cdescriptor = cls.__descriptors[field.name] |
||||
if field.label == _LABEL_REPEATED: |
||||
if field.cpp_type == _CPPTYPE_MESSAGE: |
||||
value = RepeatedCompositeProperty(field_cdescriptor, field.message_type) |
||||
else: |
||||
value = RepeatedScalarProperty(field_cdescriptor) |
||||
elif field.cpp_type == _CPPTYPE_MESSAGE: |
||||
value = CompositeProperty(field_cdescriptor, field.message_type) |
||||
else: |
||||
value = ScalarProperty(field_cdescriptor) |
||||
setattr(cls, field.name, value) |
||||
|
||||
# Attach a constant with the field number. |
||||
constant_name = field.name.upper() + '_FIELD_NUMBER' |
||||
setattr(cls, constant_name, field.number) |
||||
|
||||
def Init(self, **kwargs): |
||||
"""Message constructor.""" |
||||
cmessage = kwargs.pop('__cmessage', None) |
||||
if cmessage is None: |
||||
self._cmsg = NewCMessage(message_descriptor.full_name) |
||||
else: |
||||
self._cmsg = cmessage |
||||
|
||||
# Keep a reference to the owner, as the owner keeps a reference to the |
||||
# underlying protocol buffer message. |
||||
owner = kwargs.pop('__owner', None) |
||||
if owner is not None: |
||||
self._owner = owner |
||||
|
||||
self.Extensions = ExtensionDict(self) |
||||
self._composite_fields = {} |
||||
|
||||
for field_name, field_value in kwargs.iteritems(): |
||||
field_cdescriptor = self.__descriptors.get(field_name, None) |
||||
if field_cdescriptor is None: |
||||
raise ValueError('Protocol message has no "%s" field.' % field_name) |
||||
if field_cdescriptor.label == _LABEL_REPEATED: |
||||
if field_cdescriptor.cpp_type == _CPPTYPE_MESSAGE: |
||||
for val in field_value: |
||||
getattr(self, field_name).add().MergeFrom(val) |
||||
else: |
||||
getattr(self, field_name).extend(field_value) |
||||
elif field_cdescriptor.cpp_type == _CPPTYPE_MESSAGE: |
||||
getattr(self, field_name).MergeFrom(field_value) |
||||
else: |
||||
setattr(self, field_name, field_value) |
||||
|
||||
Init.__module__ = None |
||||
Init.__doc__ = None |
||||
cls.__init__ = Init |
||||
|
||||
|
||||
def _IsMessageSetExtension(field): |
||||
"""Checks if a field is a message set extension.""" |
||||
return (field.is_extension and |
||||
field.containing_type.has_options and |
||||
field.containing_type.GetOptions().message_set_wire_format and |
||||
field.type == _TYPE_MESSAGE and |
||||
field.message_type == field.extension_scope and |
||||
field.label == _LABEL_OPTIONAL) |
||||
|
||||
|
||||
def _AddMessageMethods(message_descriptor, cls): |
||||
"""Adds the methods to a protocol message class.""" |
||||
if message_descriptor.is_extendable: |
||||
|
||||
def ClearExtension(self, extension): |
||||
self.Extensions.ClearExtension(extension) |
||||
|
||||
def HasExtension(self, extension): |
||||
return self.Extensions.HasExtension(extension) |
||||
|
||||
def HasField(self, field_name): |
||||
return self._cmsg.HasField(field_name) |
||||
|
||||
def ClearField(self, field_name): |
||||
if field_name in self._composite_fields: |
||||
del self._composite_fields[field_name] |
||||
self._cmsg.ClearField(field_name) |
||||
|
||||
def Clear(self): |
||||
return self._cmsg.Clear() |
||||
|
||||
def IsInitialized(self, errors=None): |
||||
if self._cmsg.IsInitialized(): |
||||
return True |
||||
if errors is not None: |
||||
errors.extend(self.FindInitializationErrors()); |
||||
return False |
||||
|
||||
def SerializeToString(self): |
||||
if not self.IsInitialized(): |
||||
raise message.EncodeError( |
||||
'Message is missing required fields: ' + |
||||
','.join(self.FindInitializationErrors())) |
||||
return self._cmsg.SerializeToString() |
||||
|
||||
def SerializePartialToString(self): |
||||
return self._cmsg.SerializePartialToString() |
||||
|
||||
def ParseFromString(self, serialized): |
||||
self.Clear() |
||||
self.MergeFromString(serialized) |
||||
|
||||
def MergeFromString(self, serialized): |
||||
byte_size = self._cmsg.MergeFromString(serialized) |
||||
if byte_size < 0: |
||||
raise message.DecodeError('Unable to merge from string.') |
||||
return byte_size |
||||
|
||||
def MergeFrom(self, msg): |
||||
if not isinstance(msg, cls): |
||||
raise TypeError( |
||||
"Parameter to MergeFrom() must be instance of same class.") |
||||
self._cmsg.MergeFrom(msg._cmsg) |
||||
|
||||
def CopyFrom(self, msg): |
||||
self._cmsg.CopyFrom(msg._cmsg) |
||||
|
||||
def ByteSize(self): |
||||
return self._cmsg.ByteSize() |
||||
|
||||
def SetInParent(self): |
||||
return self._cmsg.SetInParent() |
||||
|
||||
def ListFields(self): |
||||
all_fields = [] |
||||
field_list = self._cmsg.ListFields() |
||||
fields_by_name = cls.DESCRIPTOR.fields_by_name |
||||
for is_extension, field_name in field_list: |
||||
if is_extension: |
||||
extension = cls._extensions_by_name[field_name] |
||||
all_fields.append((extension, self.Extensions[extension])) |
||||
else: |
||||
field_descriptor = fields_by_name[field_name] |
||||
all_fields.append( |
||||
(field_descriptor, getattr(self, field_name))) |
||||
all_fields.sort(key=lambda item: item[0].number) |
||||
return all_fields |
||||
|
||||
def FindInitializationErrors(self): |
||||
return self._cmsg.FindInitializationErrors() |
||||
|
||||
def __str__(self): |
||||
return self._cmsg.DebugString() |
||||
|
||||
def __eq__(self, other): |
||||
if self is other: |
||||
return True |
||||
if not isinstance(other, self.__class__): |
||||
return False |
||||
return self.ListFields() == other.ListFields() |
||||
|
||||
def __ne__(self, other): |
||||
return not self == other |
||||
|
||||
def __hash__(self): |
||||
raise TypeError('unhashable object') |
||||
|
||||
def __unicode__(self): |
||||
return text_format.MessageToString(self, as_utf8=True).decode('utf-8') |
||||
|
||||
# Attach the local methods to the message class. |
||||
for key, value in locals().copy().iteritems(): |
||||
if key not in ('key', 'value', '__builtins__', '__name__', '__doc__'): |
||||
setattr(cls, key, value) |
||||
|
||||
# Static methods: |
||||
|
||||
def RegisterExtension(extension_handle): |
||||
extension_handle.containing_type = cls.DESCRIPTOR |
||||
cls._extensions_by_name[extension_handle.full_name] = extension_handle |
||||
|
||||
if _IsMessageSetExtension(extension_handle): |
||||
# MessageSet extension. Also register under type name. |
||||
cls._extensions_by_name[ |
||||
extension_handle.message_type.full_name] = extension_handle |
||||
cls.RegisterExtension = staticmethod(RegisterExtension) |
||||
|
||||
def FromString(string): |
||||
msg = cls() |
||||
msg.MergeFromString(string) |
||||
return msg |
||||
cls.FromString = staticmethod(FromString) |
||||
|
||||
|
||||
|
||||
def _AddPropertiesForExtensions(message_descriptor, cls): |
||||
"""Adds properties for all fields in this protocol message type.""" |
||||
extension_dict = message_descriptor.extensions_by_name |
||||
for extension_name, extension_field in extension_dict.iteritems(): |
||||
constant_name = extension_name.upper() + '_FIELD_NUMBER' |
||||
setattr(cls, constant_name, extension_field.number) |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,334 @@ |
||||
// 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.
|
||||
|
||||
// Author: petar@google.com (Petar Petrov)
|
||||
|
||||
#include <Python.h> |
||||
|
||||
#include <google/protobuf/pyext/python_descriptor.h> |
||||
#include <google/protobuf/descriptor.pb.h> |
||||
|
||||
#define C(str) const_cast<char*>(str) |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace python { |
||||
|
||||
static void CFieldDescriptorDealloc(CFieldDescriptor* self); |
||||
|
||||
static google::protobuf::DescriptorPool* g_descriptor_pool = NULL; |
||||
|
||||
static PyObject* CFieldDescriptor_GetFullName( |
||||
CFieldDescriptor* self, void *closure) { |
||||
Py_XINCREF(self->full_name); |
||||
return self->full_name; |
||||
} |
||||
|
||||
static PyObject* CFieldDescriptor_GetName( |
||||
CFieldDescriptor *self, void *closure) { |
||||
Py_XINCREF(self->name); |
||||
return self->name; |
||||
} |
||||
|
||||
static PyObject* CFieldDescriptor_GetCppType( |
||||
CFieldDescriptor *self, void *closure) { |
||||
Py_XINCREF(self->cpp_type); |
||||
return self->cpp_type; |
||||
} |
||||
|
||||
static PyObject* CFieldDescriptor_GetLabel( |
||||
CFieldDescriptor *self, void *closure) { |
||||
Py_XINCREF(self->label); |
||||
return self->label; |
||||
} |
||||
|
||||
static PyObject* CFieldDescriptor_GetID( |
||||
CFieldDescriptor *self, void *closure) { |
||||
Py_XINCREF(self->id); |
||||
return self->id; |
||||
} |
||||
|
||||
|
||||
static PyGetSetDef CFieldDescriptorGetters[] = { |
||||
{ C("full_name"), |
||||
(getter)CFieldDescriptor_GetFullName, NULL, "Full name", NULL}, |
||||
{ C("name"), |
||||
(getter)CFieldDescriptor_GetName, NULL, "last name", NULL}, |
||||
{ C("cpp_type"), |
||||
(getter)CFieldDescriptor_GetCppType, NULL, "C++ Type", NULL}, |
||||
{ C("label"), |
||||
(getter)CFieldDescriptor_GetLabel, NULL, "Label", NULL}, |
||||
{ C("id"), |
||||
(getter)CFieldDescriptor_GetID, NULL, "ID", NULL}, |
||||
{NULL} |
||||
}; |
||||
|
||||
PyTypeObject CFieldDescriptor_Type = { |
||||
PyObject_HEAD_INIT(&PyType_Type) |
||||
0, |
||||
C("google3.net.google.protobuf.python.internal." |
||||
"_net_proto2___python." |
||||
"CFieldDescriptor"), // tp_name
|
||||
sizeof(CFieldDescriptor), // tp_basicsize
|
||||
0, // tp_itemsize
|
||||
(destructor)CFieldDescriptorDealloc, // tp_dealloc
|
||||
0, // tp_print
|
||||
0, // tp_getattr
|
||||
0, // tp_setattr
|
||||
0, // tp_compare
|
||||
0, // tp_repr
|
||||
0, // tp_as_number
|
||||
0, // tp_as_sequence
|
||||
0, // tp_as_mapping
|
||||
0, // tp_hash
|
||||
0, // tp_call
|
||||
0, // tp_str
|
||||
0, // tp_getattro
|
||||
0, // tp_setattro
|
||||
0, // tp_as_buffer
|
||||
Py_TPFLAGS_DEFAULT, // tp_flags
|
||||
C("A Field Descriptor"), // tp_doc
|
||||
0, // tp_traverse
|
||||
0, // tp_clear
|
||||
0, // tp_richcompare
|
||||
0, // tp_weaklistoffset
|
||||
0, // tp_iter
|
||||
0, // tp_iternext
|
||||
0, // tp_methods
|
||||
0, // tp_members
|
||||
CFieldDescriptorGetters, // tp_getset
|
||||
0, // tp_base
|
||||
0, // tp_dict
|
||||
0, // tp_descr_get
|
||||
0, // tp_descr_set
|
||||
0, // tp_dictoffset
|
||||
0, // tp_init
|
||||
PyType_GenericAlloc, // tp_alloc
|
||||
PyType_GenericNew, // tp_new
|
||||
PyObject_Del, // tp_free
|
||||
}; |
||||
|
||||
static void CFieldDescriptorDealloc(CFieldDescriptor* self) { |
||||
Py_DECREF(self->full_name); |
||||
Py_DECREF(self->name); |
||||
Py_DECREF(self->cpp_type); |
||||
Py_DECREF(self->label); |
||||
Py_DECREF(self->id); |
||||
self->ob_type->tp_free(reinterpret_cast<PyObject*>(self)); |
||||
} |
||||
|
||||
typedef struct { |
||||
PyObject_HEAD |
||||
|
||||
const google::protobuf::DescriptorPool* pool; |
||||
} CDescriptorPool; |
||||
|
||||
static void CDescriptorPoolDealloc(CDescriptorPool* self); |
||||
|
||||
static PyObject* CDescriptorPool_NewCDescriptor( |
||||
const google::protobuf::FieldDescriptor* field_descriptor) { |
||||
CFieldDescriptor* cfield_descriptor = PyObject_New( |
||||
CFieldDescriptor, &CFieldDescriptor_Type); |
||||
if (cfield_descriptor == NULL) { |
||||
return NULL; |
||||
} |
||||
cfield_descriptor->descriptor = field_descriptor; |
||||
|
||||
cfield_descriptor->full_name = PyString_FromString( |
||||
field_descriptor->full_name().c_str()); |
||||
cfield_descriptor->name = PyString_FromString( |
||||
field_descriptor->name().c_str()); |
||||
cfield_descriptor->cpp_type = PyLong_FromLong(field_descriptor->cpp_type()); |
||||
cfield_descriptor->label = PyLong_FromLong(field_descriptor->label()); |
||||
cfield_descriptor->id = PyLong_FromVoidPtr(cfield_descriptor); |
||||
return reinterpret_cast<PyObject*>(cfield_descriptor); |
||||
} |
||||
|
||||
static PyObject* CDescriptorPool_FindFieldByName( |
||||
CDescriptorPool* self, PyObject* arg) { |
||||
const char* full_field_name = PyString_AsString(arg); |
||||
if (full_field_name == NULL) { |
||||
return NULL; |
||||
} |
||||
|
||||
const google::protobuf::FieldDescriptor* field_descriptor = NULL; |
||||
|
||||
field_descriptor = self->pool->FindFieldByName(full_field_name); |
||||
if (field_descriptor == NULL) { |
||||
PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s", |
||||
full_field_name); |
||||
return NULL; |
||||
} |
||||
|
||||
return CDescriptorPool_NewCDescriptor(field_descriptor); |
||||
} |
||||
|
||||
static PyObject* CDescriptorPool_FindExtensionByName( |
||||
CDescriptorPool* self, PyObject* arg) { |
||||
const char* full_field_name = PyString_AsString(arg); |
||||
if (full_field_name == NULL) { |
||||
return NULL; |
||||
} |
||||
|
||||
const google::protobuf::FieldDescriptor* field_descriptor = |
||||
self->pool->FindExtensionByName(full_field_name); |
||||
if (field_descriptor == NULL) { |
||||
PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s", |
||||
full_field_name); |
||||
return NULL; |
||||
} |
||||
|
||||
return CDescriptorPool_NewCDescriptor(field_descriptor); |
||||
} |
||||
|
||||
static PyMethodDef CDescriptorPoolMethods[] = { |
||||
{ C("FindFieldByName"), |
||||
(PyCFunction)CDescriptorPool_FindFieldByName, |
||||
METH_O, |
||||
C("Searches for a field descriptor by full name.") }, |
||||
{ C("FindExtensionByName"), |
||||
(PyCFunction)CDescriptorPool_FindExtensionByName, |
||||
METH_O, |
||||
C("Searches for extension descriptor by full name.") }, |
||||
{NULL} |
||||
}; |
||||
|
||||
PyTypeObject CDescriptorPool_Type = { |
||||
PyObject_HEAD_INIT(&PyType_Type) |
||||
0, |
||||
C("google3.net.google.protobuf.python.internal." |
||||
"_net_proto2___python." |
||||
"CFieldDescriptor"), // tp_name
|
||||
sizeof(CDescriptorPool), // tp_basicsize
|
||||
0, // tp_itemsize
|
||||
(destructor)CDescriptorPoolDealloc, // tp_dealloc
|
||||
0, // tp_print
|
||||
0, // tp_getattr
|
||||
0, // tp_setattr
|
||||
0, // tp_compare
|
||||
0, // tp_repr
|
||||
0, // tp_as_number
|
||||
0, // tp_as_sequence
|
||||
0, // tp_as_mapping
|
||||
0, // tp_hash
|
||||
0, // tp_call
|
||||
0, // tp_str
|
||||
0, // tp_getattro
|
||||
0, // tp_setattro
|
||||
0, // tp_as_buffer
|
||||
Py_TPFLAGS_DEFAULT, // tp_flags
|
||||
C("A Descriptor Pool"), // tp_doc
|
||||
0, // tp_traverse
|
||||
0, // tp_clear
|
||||
0, // tp_richcompare
|
||||
0, // tp_weaklistoffset
|
||||
0, // tp_iter
|
||||
0, // tp_iternext
|
||||
CDescriptorPoolMethods, // tp_methods
|
||||
0, // tp_members
|
||||
0, // tp_getset
|
||||
0, // tp_base
|
||||
0, // tp_dict
|
||||
0, // tp_descr_get
|
||||
0, // tp_descr_set
|
||||
0, // tp_dictoffset
|
||||
0, // tp_init
|
||||
PyType_GenericAlloc, // tp_alloc
|
||||
PyType_GenericNew, // tp_new
|
||||
PyObject_Del, // tp_free
|
||||
}; |
||||
|
||||
static void CDescriptorPoolDealloc(CDescriptorPool* self) { |
||||
self->ob_type->tp_free(reinterpret_cast<PyObject*>(self)); |
||||
} |
||||
|
||||
google::protobuf::DescriptorPool* GetDescriptorPool() { |
||||
if (g_descriptor_pool == NULL) { |
||||
g_descriptor_pool = new google::protobuf::DescriptorPool( |
||||
google::protobuf::DescriptorPool::generated_pool()); |
||||
} |
||||
return g_descriptor_pool; |
||||
} |
||||
|
||||
PyObject* Python_NewCDescriptorPool(PyObject* ignored, PyObject* args) { |
||||
CDescriptorPool* cdescriptor_pool = PyObject_New( |
||||
CDescriptorPool, &CDescriptorPool_Type); |
||||
if (cdescriptor_pool == NULL) { |
||||
return NULL; |
||||
} |
||||
cdescriptor_pool->pool = GetDescriptorPool(); |
||||
return reinterpret_cast<PyObject*>(cdescriptor_pool); |
||||
} |
||||
|
||||
PyObject* Python_BuildFile(PyObject* ignored, PyObject* arg) { |
||||
char* message_type; |
||||
Py_ssize_t message_len; |
||||
|
||||
if (PyString_AsStringAndSize(arg, &message_type, &message_len) < 0) { |
||||
return NULL; |
||||
} |
||||
|
||||
google::protobuf::FileDescriptorProto file_proto; |
||||
if (!file_proto.ParseFromArray(message_type, message_len)) { |
||||
PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!"); |
||||
return NULL; |
||||
} |
||||
|
||||
// If this file is already in the generated pool, don't add it again.
|
||||
if (google::protobuf::DescriptorPool::generated_pool()->FindFileByName( |
||||
file_proto.name()) != NULL) { |
||||
Py_RETURN_NONE; |
||||
} |
||||
|
||||
const google::protobuf::FileDescriptor* descriptor = GetDescriptorPool()->BuildFile( |
||||
file_proto); |
||||
if (descriptor == NULL) { |
||||
PyErr_SetString(PyExc_TypeError, |
||||
"Couldn't build proto file into descriptor pool!"); |
||||
return NULL; |
||||
} |
||||
|
||||
Py_RETURN_NONE; |
||||
} |
||||
|
||||
bool InitDescriptor() { |
||||
CFieldDescriptor_Type.tp_new = PyType_GenericNew; |
||||
if (PyType_Ready(&CFieldDescriptor_Type) < 0) |
||||
return false; |
||||
|
||||
CDescriptorPool_Type.tp_new = PyType_GenericNew; |
||||
if (PyType_Ready(&CDescriptorPool_Type) < 0) |
||||
return false; |
||||
return true; |
||||
} |
||||
|
||||
} // namespace python
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,87 @@ |
||||
// 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.
|
||||
|
||||
// Author: petar@google.com (Petar Petrov)
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_PYTHON_DESCRIPTOR_H__ |
||||
#define GOOGLE_PROTOBUF_PYTHON_DESCRIPTOR_H__ |
||||
|
||||
#include <Python.h> |
||||
#include <structmember.h> |
||||
|
||||
#include <google/protobuf/descriptor.h> |
||||
|
||||
#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) |
||||
typedef int Py_ssize_t; |
||||
#define PY_SSIZE_T_MAX INT_MAX |
||||
#define PY_SSIZE_T_MIN INT_MIN |
||||
#endif |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace python { |
||||
|
||||
typedef struct { |
||||
PyObject_HEAD |
||||
|
||||
// The proto2 descriptor that this object represents.
|
||||
const google::protobuf::FieldDescriptor* descriptor; |
||||
|
||||
// Full name of the field (PyString).
|
||||
PyObject* full_name; |
||||
|
||||
// Name of the field (PyString).
|
||||
PyObject* name; |
||||
|
||||
// C++ type of the field (PyLong).
|
||||
PyObject* cpp_type; |
||||
|
||||
// Name of the field (PyLong).
|
||||
PyObject* label; |
||||
|
||||
// Identity of the descriptor (PyLong used as a poiner).
|
||||
PyObject* id; |
||||
} CFieldDescriptor; |
||||
|
||||
extern PyTypeObject CFieldDescriptor_Type; |
||||
|
||||
extern PyTypeObject CDescriptorPool_Type; |
||||
|
||||
|
||||
PyObject* Python_NewCDescriptorPool(PyObject* ignored, PyObject* args); |
||||
PyObject* Python_BuildFile(PyObject* ignored, PyObject* args); |
||||
bool InitDescriptor(); |
||||
google::protobuf::DescriptorPool* GetDescriptorPool(); |
||||
|
||||
} // namespace python
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_PYTHON_DESCRIPTOR_H__
|
@ -0,0 +1,63 @@ |
||||
// 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.
|
||||
|
||||
// Author: qrczak@google.com (Marcin Kowalczyk)
|
||||
|
||||
#include <google/protobuf/pyext/python_protobuf.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace python { |
||||
|
||||
static const Message* GetCProtoInsidePyProtoStub(PyObject* msg) { |
||||
return NULL; |
||||
} |
||||
static Message* MutableCProtoInsidePyProtoStub(PyObject* msg) { |
||||
return NULL; |
||||
} |
||||
|
||||
// This is initialized with a default, stub implementation.
|
||||
// If python-google.protobuf.cc is loaded, the function pointer is overridden
|
||||
// with a full implementation.
|
||||
const Message* (*GetCProtoInsidePyProtoPtr)(PyObject* msg) = |
||||
GetCProtoInsidePyProtoStub; |
||||
Message* (*MutableCProtoInsidePyProtoPtr)(PyObject* msg) = |
||||
MutableCProtoInsidePyProtoStub; |
||||
|
||||
const Message* GetCProtoInsidePyProto(PyObject* msg) { |
||||
return GetCProtoInsidePyProtoPtr(msg); |
||||
} |
||||
Message* MutableCProtoInsidePyProto(PyObject* msg) { |
||||
return MutableCProtoInsidePyProtoPtr(msg); |
||||
} |
||||
|
||||
} // namespace python
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,57 @@ |
||||
// 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.
|
||||
|
||||
// Author: qrczak@google.com (Marcin Kowalczyk)
|
||||
//
|
||||
// This module exposes the C proto inside the given Python proto, in
|
||||
// case the Python proto is implemented with a C proto.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_PYTHON_PYTHON_PROTOBUF_H__ |
||||
#define GOOGLE_PROTOBUF_PYTHON_PYTHON_PROTOBUF_H__ |
||||
|
||||
#include <Python.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
|
||||
class Message; |
||||
|
||||
namespace python { |
||||
|
||||
// Return the pointer to the C proto inside the given Python proto,
|
||||
// or NULL when this is not a Python proto implemented with a C proto.
|
||||
const Message* GetCProtoInsidePyProto(PyObject* msg); |
||||
Message* MutableCProtoInsidePyProto(PyObject* msg); |
||||
|
||||
} // namespace python
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_PYTHON_PYTHON_PROTOBUF_H__
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue