Submit recent changes from internal branch, including "lite mode" for

C++ and Java.  See CHANGES.txt for more details.
This commit is contained in:
kenton@google.com 2009-07-29 01:13:20 +00:00
parent d2fd0638c3
commit 80b1d62bfc
130 changed files with 16247 additions and 6817 deletions

View File

@ -1,6 +1,9 @@
????-??-?? version 2.1.1:
????-??-?? version 2.2.0:
C++
* Lite mode: The "optimize_for = LITE_RUNTIME" option causes the compiler
to generate code which only depends libprotobuf-lite, which is much smaller
than libprotobuf but lacks descriptors, reflection, and some other features.
* Fixed bug where Message.Swap(Message) was only implemented for
optimize_for_speed. Swap now properly implemented in both modes
(Issue 91).
@ -10,6 +13,27 @@
* Floating-point literals in generated code that are intended to be
single-precision now explicitly have 'f' suffix to avoid pedantic warnings
produced by some compilers.
* The [deprecated=true] option now causes the C++ code generator to generate
a GCC-style deprecation annotation (no-op on other compilers).
* google::protobuf::GetEnumDescriptor<SomeGeneratedEnumType>() returns the
EnumDescriptor for that type -- useful for templates which cannot call
SomeGeneratedEnumType_descriptor().
* Various optimizations and obscure bug fixes.
Java
* Lite mode: The "optimize_for = LITE_RUNTIME" option causes the compiler
to generate code which only depends libprotobuf-lite, which is much smaller
than libprotobuf but lacks descriptors, reflection, and some other features.
* Put Builder objects on a freelist after build() is called, so they may be
reused later.
* Lots of style cleanups.
Python
* Fixed endianness bug with floats and doubles.
* Text format parsing support.
* Fix bug with parsing packed repeated fields in embedded messages.
* Ability to initialize fields by passing keyword args to constructor.
* Support iterators in extend and __setslice__ for containers.
2009-05-13 version 2.1.0:

View File

@ -62,6 +62,7 @@ EXTRA_DIST = \
examples/add_person.py \
examples/list_people.py \
java/src/main/java/com/google/protobuf/AbstractMessage.java \
java/src/main/java/com/google/protobuf/AbstractMessageLite.java \
java/src/main/java/com/google/protobuf/BlockingRpcChannel.java \
java/src/main/java/com/google/protobuf/BlockingService.java \
java/src/main/java/com/google/protobuf/ByteString.java \
@ -70,10 +71,14 @@ EXTRA_DIST = \
java/src/main/java/com/google/protobuf/Descriptors.java \
java/src/main/java/com/google/protobuf/DynamicMessage.java \
java/src/main/java/com/google/protobuf/ExtensionRegistry.java \
java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java \
java/src/main/java/com/google/protobuf/FieldSet.java \
java/src/main/java/com/google/protobuf/GeneratedMessage.java \
java/src/main/java/com/google/protobuf/GeneratedMessageLite.java \
java/src/main/java/com/google/protobuf/Internal.java \
java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java \
java/src/main/java/com/google/protobuf/Message.java \
java/src/main/java/com/google/protobuf/MessageLite.java \
java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java \
java/src/main/java/com/google/protobuf/RpcCallback.java \
java/src/main/java/com/google/protobuf/RpcChannel.java \
@ -91,6 +96,7 @@ EXTRA_DIST = \
java/src/test/java/com/google/protobuf/DescriptorsTest.java \
java/src/test/java/com/google/protobuf/DynamicMessageTest.java \
java/src/test/java/com/google/protobuf/GeneratedMessageTest.java \
java/src/test/java/com/google/protobuf/LiteTest.java \
java/src/test/java/com/google/protobuf/MessageTest.java \
java/src/test/java/com/google/protobuf/ServiceTest.java \
java/src/test/java/com/google/protobuf/TestUtil.java \
@ -110,6 +116,7 @@ EXTRA_DIST = \
python/google/protobuf/internal/input_stream.py \
python/google/protobuf/internal/input_stream_test.py \
python/google/protobuf/internal/message_listener.py \
python/google/protobuf/internal/message_test.py \
python/google/protobuf/internal/more_extensions.proto \
python/google/protobuf/internal/more_messages.proto \
python/google/protobuf/internal/output_stream.py \

View File

@ -5,6 +5,10 @@
# itself, they cannot be generated automatically by a make rule. "make check"
# will fail if these files do not match what the protocol compiler would
# generate.
#
# HINT: Flags passed to generate_descriptor_proto.sh will be passed directly
# to make when building protoc. This is particularly useful for passing
# -j4 to run 4 jobs simultaneously.
if test ! -e src/google/protobuf/stubs/common.h; then
cat >&2 << __EOF__
@ -23,5 +27,5 @@ __EOF__
fi
cd src
make protoc && ./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:. google/protobuf/descriptor.proto
make $@ protoc && ./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:. google/protobuf/descriptor.proto
cd ..

View File

@ -124,6 +124,9 @@
value="../src/google/protobuf/unittest_optimize_for.proto" />
<arg
value="../src/google/protobuf/unittest_custom_options.proto" />
<arg value="../src/google/protobuf/unittest_lite.proto" />
<arg value="../src/google/protobuf/unittest_import_lite.proto" />
<arg value="../src/google/protobuf/unittest_lite_imports_nonlite.proto" />
</exec>
</tasks>
<testSourceRoot>target/generated-test-sources</testSourceRoot>

View File

@ -30,12 +30,12 @@
package com.google.protobuf;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import java.io.FilterInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -45,11 +45,12 @@ import java.util.Map;
*
* @author kenton@google.com Kenton Varda
*/
public abstract class AbstractMessage implements Message {
public abstract class AbstractMessage extends AbstractMessageLite
implements Message {
@SuppressWarnings("unchecked")
public boolean isInitialized() {
// Check that all required fields are present.
for (FieldDescriptor field : getDescriptorForType().getFields()) {
for (final FieldDescriptor field : getDescriptorForType().getFields()) {
if (field.isRequired()) {
if (!hasField(field)) {
return false;
@ -58,11 +59,12 @@ public abstract class AbstractMessage implements Message {
}
// Check that embedded messages are initialized.
for (Map.Entry<FieldDescriptor, Object> entry : getAllFields().entrySet()) {
FieldDescriptor field = entry.getKey();
for (final Map.Entry<FieldDescriptor, Object> entry :
getAllFields().entrySet()) {
final FieldDescriptor field = entry.getKey();
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
if (field.isRepeated()) {
for (Message element : (List<Message>) entry.getValue()) {
for (final Message element : (List<Message>) entry.getValue()) {
if (!element.isInitialized()) {
return false;
}
@ -83,117 +85,59 @@ public abstract class AbstractMessage implements Message {
return TextFormat.printToString(this);
}
public void writeTo(CodedOutputStream output) throws IOException {
for (Map.Entry<FieldDescriptor, Object> entry : getAllFields().entrySet()) {
FieldDescriptor field = entry.getKey();
if (field.isRepeated()) {
List valueList = (List) entry.getValue();
if (field.getOptions().getPacked()) {
public void writeTo(final CodedOutputStream output) throws IOException {
final boolean isMessageSet =
getDescriptorForType().getOptions().getMessageSetWireFormat();
output.writeTag(field.getNumber(),
WireFormat.WIRETYPE_LENGTH_DELIMITED);
int dataSize = 0;
for (Object element : valueList) {
dataSize += CodedOutputStream.computeFieldSizeNoTag(
field.getType(), element);
}
output.writeRawVarint32(dataSize);
for (Object element : valueList) {
output.writeFieldNoTag(field.getType(), element);
}
} else {
for (Object element : valueList) {
output.writeField(field.getType(), field.getNumber(), element);
}
}
for (final Map.Entry<FieldDescriptor, Object> entry :
getAllFields().entrySet()) {
final FieldDescriptor field = entry.getKey();
final Object value = entry.getValue();
if (isMessageSet && field.isExtension() &&
field.getType() == FieldDescriptor.Type.MESSAGE &&
!field.isRepeated()) {
output.writeMessageSetExtension(field.getNumber(), (Message) value);
} else {
output.writeField(field.getType(), field.getNumber(), entry.getValue());
FieldSet.writeField(field, value, output);
}
}
UnknownFieldSet unknownFields = getUnknownFields();
if (getDescriptorForType().getOptions().getMessageSetWireFormat()) {
final UnknownFieldSet unknownFields = getUnknownFields();
if (isMessageSet) {
unknownFields.writeAsMessageSetTo(output);
} else {
unknownFields.writeTo(output);
}
}
public ByteString toByteString() {
try {
ByteString.CodedBuilder out =
ByteString.newCodedBuilder(getSerializedSize());
writeTo(out.getCodedOutput());
return out.build();
} catch (IOException e) {
throw new RuntimeException(
"Serializing to a ByteString threw an IOException (should " +
"never happen).", e);
}
}
public byte[] toByteArray() {
try {
byte[] result = new byte[getSerializedSize()];
CodedOutputStream output = CodedOutputStream.newInstance(result);
writeTo(output);
output.checkNoSpaceLeft();
return result;
} catch (IOException e) {
throw new RuntimeException(
"Serializing to a byte array threw an IOException " +
"(should never happen).", e);
}
}
public void writeTo(OutputStream output) throws IOException {
CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
writeTo(codedOutput);
codedOutput.flush();
}
public void writeDelimitedTo(OutputStream output) throws IOException {
CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
codedOutput.writeRawVarint32(getSerializedSize());
writeTo(codedOutput);
codedOutput.flush();
}
private int memoizedSize = -1;
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) return size;
if (size != -1) {
return size;
}
size = 0;
for (Map.Entry<FieldDescriptor, Object> entry : getAllFields().entrySet()) {
FieldDescriptor field = entry.getKey();
if (field.isRepeated()) {
List valueList = (List) entry.getValue();
if (field.getOptions().getPacked()) {
int dataSize = 0;
for (Object element : valueList) {
dataSize += CodedOutputStream.computeFieldSizeNoTag(
field.getType(), element);
}
size += dataSize;
size += CodedOutputStream.computeTagSize(field.getNumber());
size += CodedOutputStream.computeRawVarint32Size(dataSize);
} else {
for (Object element : valueList) {
size += CodedOutputStream.computeFieldSize(
field.getType(), field.getNumber(), element);
}
}
final boolean isMessageSet =
getDescriptorForType().getOptions().getMessageSetWireFormat();
for (final Map.Entry<FieldDescriptor, Object> entry :
getAllFields().entrySet()) {
final FieldDescriptor field = entry.getKey();
final Object value = entry.getValue();
if (isMessageSet && field.isExtension() &&
field.getType() == FieldDescriptor.Type.MESSAGE &&
!field.isRepeated()) {
size += CodedOutputStream.computeMessageSetExtensionSize(
field.getNumber(), (Message) value);
} else {
size += CodedOutputStream.computeFieldSize(
field.getType(), field.getNumber(), entry.getValue());
size += FieldSet.computeFieldSize(field, value);
}
}
UnknownFieldSet unknownFields = getUnknownFields();
if (getDescriptorForType().getOptions().getMessageSetWireFormat()) {
final UnknownFieldSet unknownFields = getUnknownFields();
if (isMessageSet) {
size += unknownFields.getSerializedSizeAsMessageSet();
} else {
size += unknownFields.getSerializedSize();
@ -204,14 +148,14 @@ public abstract class AbstractMessage implements Message {
}
@Override
public boolean equals(Object other) {
public boolean equals(final Object other) {
if (other == this) {
return true;
}
if (!(other instanceof Message)) {
return false;
}
Message otherMessage = (Message) other;
final Message otherMessage = (Message) other;
if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
return false;
}
@ -237,20 +181,21 @@ public abstract class AbstractMessage implements Message {
*/
@SuppressWarnings("unchecked")
public static abstract class Builder<BuilderType extends Builder>
extends AbstractMessageLite.Builder<BuilderType>
implements Message.Builder {
// The compiler produces an error if this is not declared explicitly.
@Override
public abstract BuilderType clone();
public BuilderType clear() {
for (Map.Entry<FieldDescriptor, Object> entry :
for (final Map.Entry<FieldDescriptor, Object> entry :
getAllFields().entrySet()) {
clearField(entry.getKey());
}
return (BuilderType) this;
}
public BuilderType mergeFrom(Message other) {
public BuilderType mergeFrom(final Message other) {
if (other.getDescriptorForType() != getDescriptorForType()) {
throw new IllegalArgumentException(
"mergeFrom(Message) can only merge messages of the same type.");
@ -265,15 +210,15 @@ public abstract class AbstractMessage implements Message {
// TODO(kenton): Provide a function somewhere called makeDeepCopy()
// which allows people to make secure deep copies of messages.
for (Map.Entry<FieldDescriptor, Object> entry :
for (final Map.Entry<FieldDescriptor, Object> entry :
other.getAllFields().entrySet()) {
FieldDescriptor field = entry.getKey();
final FieldDescriptor field = entry.getKey();
if (field.isRepeated()) {
for (Object element : (List)entry.getValue()) {
for (final Object element : (List)entry.getValue()) {
addRepeatedField(field, element);
}
} else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
Message existingValue = (Message)getField(field);
final Message existingValue = (Message)getField(field);
if (existingValue == existingValue.getDefaultInstanceForType()) {
setField(field, entry.getValue());
} else {
@ -288,24 +233,288 @@ public abstract class AbstractMessage implements Message {
}
}
mergeUnknownFields(other.getUnknownFields());
return (BuilderType) this;
}
public BuilderType mergeFrom(CodedInputStream input) throws IOException {
@Override
public BuilderType mergeFrom(final CodedInputStream input)
throws IOException {
return mergeFrom(input, ExtensionRegistry.getEmptyRegistry());
}
public BuilderType mergeFrom(CodedInputStream input,
ExtensionRegistry extensionRegistry)
throws IOException {
UnknownFieldSet.Builder unknownFields =
@Override
public BuilderType mergeFrom(
final CodedInputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
final UnknownFieldSet.Builder unknownFields =
UnknownFieldSet.newBuilder(getUnknownFields());
FieldSet.mergeFrom(input, unknownFields, extensionRegistry, this);
while (true) {
final int tag = input.readTag();
if (tag == 0) {
break;
}
if (!mergeFieldFrom(input, unknownFields, extensionRegistry,
this, tag)) {
// end group tag
break;
}
}
setUnknownFields(unknownFields.build());
return (BuilderType) this;
}
public BuilderType mergeUnknownFields(UnknownFieldSet unknownFields) {
/**
* Like {@link #mergeFrom(CodedInputStream, UnknownFieldSet.Builder,
* ExtensionRegistryLite, Message.Builder)}, but parses a single field.
* Package-private because it is used by GeneratedMessage.ExtendableMessage.
* @param tag The tag, which should have already been read.
* @return {@code true} unless the tag is an end-group tag.
*/
@SuppressWarnings("unchecked")
static boolean mergeFieldFrom(
final CodedInputStream input,
final UnknownFieldSet.Builder unknownFields,
final ExtensionRegistryLite extensionRegistry,
final Message.Builder builder,
final int tag) throws IOException {
final Descriptor type = builder.getDescriptorForType();
if (type.getOptions().getMessageSetWireFormat() &&
tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
mergeMessageSetExtensionFromCodedStream(
input, unknownFields, extensionRegistry, builder);
return true;
}
final int wireType = WireFormat.getTagWireType(tag);
final int fieldNumber = WireFormat.getTagFieldNumber(tag);
final FieldDescriptor field;
Message defaultInstance = null;
if (type.isExtensionNumber(fieldNumber)) {
// extensionRegistry may be either ExtensionRegistry or
// ExtensionRegistryLite. Since the type we are parsing is a full
// message, only a full ExtensionRegistry could possibly contain
// extensions of it. Otherwise we will treat the registry as if it
// were empty.
if (extensionRegistry instanceof ExtensionRegistry) {
final ExtensionRegistry.ExtensionInfo extension =
((ExtensionRegistry) extensionRegistry)
.findExtensionByNumber(type, fieldNumber);
if (extension == null) {
field = null;
} else {
field = extension.descriptor;
defaultInstance = extension.defaultInstance;
}
} else {
field = null;
}
} else {
field = type.findFieldByNumber(fieldNumber);
}
if (field == null || wireType !=
FieldSet.getWireFormatForFieldType(
field.getLiteType(),
field.getOptions().getPacked())) {
// Unknown field or wrong wire type. Skip.
return unknownFields.mergeFieldFrom(tag, input);
}
if (field.getOptions().getPacked()) {
final int length = input.readRawVarint32();
final int limit = input.pushLimit(length);
if (field.getLiteType() == WireFormat.FieldType.ENUM) {
while (input.getBytesUntilLimit() > 0) {
final int rawValue = input.readEnum();
final Object value = field.getEnumType().findValueByNumber(rawValue);
if (value == null) {
// If the number isn't recognized as a valid value for this
// enum, drop it (don't even add it to unknownFields).
return true;
}
builder.addRepeatedField(field, value);
}
} else {
while (input.getBytesUntilLimit() > 0) {
final Object value =
FieldSet.readPrimitiveField(input, field.getLiteType());
builder.addRepeatedField(field, value);
}
}
input.popLimit(limit);
} else {
final Object value;
switch (field.getType()) {
case GROUP: {
final Message.Builder subBuilder;
if (defaultInstance != null) {
subBuilder = defaultInstance.newBuilderForType();
} else {
subBuilder = builder.newBuilderForField(field);
}
if (!field.isRepeated()) {
subBuilder.mergeFrom((Message) builder.getField(field));
}
input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
value = subBuilder.build();
break;
}
case MESSAGE: {
final Message.Builder subBuilder;
if (defaultInstance != null) {
subBuilder = defaultInstance.newBuilderForType();
} else {
subBuilder = builder.newBuilderForField(field);
}
if (!field.isRepeated()) {
subBuilder.mergeFrom((Message) builder.getField(field));
}
input.readMessage(subBuilder, extensionRegistry);
value = subBuilder.build();
break;
}
case ENUM:
final int rawValue = input.readEnum();
value = field.getEnumType().findValueByNumber(rawValue);
// If the number isn't recognized as a valid value for this enum,
// drop it.
if (value == null) {
unknownFields.mergeVarintField(fieldNumber, rawValue);
return true;
}
break;
default:
value = FieldSet.readPrimitiveField(input, field.getLiteType());
break;
}
if (field.isRepeated()) {
builder.addRepeatedField(field, value);
} else {
builder.setField(field, value);
}
}
return true;
}
/** Called by {@code #mergeFieldFrom()} to parse a MessageSet extension. */
private static void mergeMessageSetExtensionFromCodedStream(
final CodedInputStream input,
final UnknownFieldSet.Builder unknownFields,
final ExtensionRegistryLite extensionRegistry,
final Message.Builder builder) throws IOException {
final Descriptor type = builder.getDescriptorForType();
// The wire format for MessageSet is:
// message MessageSet {
// repeated group Item = 1 {
// required int32 typeId = 2;
// required bytes message = 3;
// }
// }
// "typeId" is the extension's field number. The extension can only be
// a message type, where "message" contains the encoded bytes of that
// message.
//
// In practice, we will probably never see a MessageSet item in which
// the message appears before the type ID, or where either field does not
// appear exactly once. However, in theory such cases are valid, so we
// should be prepared to accept them.
int typeId = 0;
ByteString rawBytes = null; // If we encounter "message" before "typeId"
Message.Builder subBuilder = null;
FieldDescriptor field = null;
while (true) {
final int tag = input.readTag();
if (tag == 0) {
break;
}
if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
typeId = input.readUInt32();
// Zero is not a valid type ID.
if (typeId != 0) {
final ExtensionRegistry.ExtensionInfo extension;
// extensionRegistry may be either ExtensionRegistry or
// ExtensionRegistryLite. Since the type we are parsing is a full
// message, only a full ExtensionRegistry could possibly contain
// extensions of it. Otherwise we will treat the registry as if it
// were empty.
if (extensionRegistry instanceof ExtensionRegistry) {
extension = ((ExtensionRegistry) extensionRegistry)
.findExtensionByNumber(type, typeId);
} else {
extension = null;
}
if (extension != null) {
field = extension.descriptor;
subBuilder = extension.defaultInstance.newBuilderForType();
final Message originalMessage = (Message)builder.getField(field);
if (originalMessage != null) {
subBuilder.mergeFrom(originalMessage);
}
if (rawBytes != null) {
// We already encountered the message. Parse it now.
subBuilder.mergeFrom(
CodedInputStream.newInstance(rawBytes.newInput()));
rawBytes = null;
}
} else {
// Unknown extension number. If we already saw data, put it
// in rawBytes.
if (rawBytes != null) {
unknownFields.mergeField(typeId,
UnknownFieldSet.Field.newBuilder()
.addLengthDelimited(rawBytes)
.build());
rawBytes = null;
}
}
}
} else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
if (typeId == 0) {
// We haven't seen a type ID yet, so we have to store the raw bytes
// for now.
rawBytes = input.readBytes();
} else if (subBuilder == null) {
// We don't know how to parse this. Ignore it.
unknownFields.mergeField(typeId,
UnknownFieldSet.Field.newBuilder()
.addLengthDelimited(input.readBytes())
.build());
} else {
// We already know the type, so we can parse directly from the input
// with no copying. Hooray!
input.readMessage(subBuilder, extensionRegistry);
}
} else {
// Unknown tag. Skip it.
if (!input.skipField(tag)) {
break; // end of group
}
}
}
input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
if (subBuilder != null) {
builder.setField(field, subBuilder.build());
}
}
public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
setUnknownFields(
UnknownFieldSet.newBuilder(getUnknownFields())
.mergeFrom(unknownFields)
@ -313,145 +522,169 @@ public abstract class AbstractMessage implements Message {
return (BuilderType) this;
}
public BuilderType mergeFrom(ByteString data)
throws InvalidProtocolBufferException {
try {
CodedInputStream input = data.newCodedInput();
mergeFrom(input);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a ByteString threw an IOException (should " +
"never happen).", e);
/**
* Construct an UninitializedMessageException reporting missing fields in
* the given message.
*/
protected static UninitializedMessageException
newUninitializedMessageException(Message message) {
return new UninitializedMessageException(findMissingFields(message));
}
/**
* Populates {@code this.missingFields} with the full "path" of each
* missing required field in the given message.
*/
private static List<String> findMissingFields(final Message message) {
final List<String> results = new ArrayList<String>();
findMissingFields(message, "", results);
return results;
}
/** Recursive helper implementing {@link #findMissingFields(Message)}. */
private static void findMissingFields(final Message message,
final String prefix,
final List<String> results) {
for (final FieldDescriptor field :
message.getDescriptorForType().getFields()) {
if (field.isRequired() && !message.hasField(field)) {
results.add(prefix + field.getName());
}
}
for (final Map.Entry<FieldDescriptor, Object> entry :
message.getAllFields().entrySet()) {
final FieldDescriptor field = entry.getKey();
final Object value = entry.getValue();
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
if (field.isRepeated()) {
int i = 0;
for (final Object element : (List) value) {
findMissingFields((Message) element,
subMessagePrefix(prefix, field, i++),
results);
}
} else {
if (message.hasField(field)) {
findMissingFields((Message) value,
subMessagePrefix(prefix, field, -1),
results);
}
}
}
}
}
public BuilderType mergeFrom(ByteString data,
ExtensionRegistry extensionRegistry)
throws InvalidProtocolBufferException {
try {
CodedInputStream input = data.newCodedInput();
mergeFrom(input, extensionRegistry);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a ByteString threw an IOException (should " +
"never happen).", e);
private static String subMessagePrefix(final String prefix,
final FieldDescriptor field,
final int index) {
final StringBuilder result = new StringBuilder(prefix);
if (field.isExtension()) {
result.append('(')
.append(field.getFullName())
.append(')');
} else {
result.append(field.getName());
}
}
public BuilderType mergeFrom(byte[] data)
throws InvalidProtocolBufferException {
return mergeFrom(data, 0, data.length);
}
public BuilderType mergeFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException {
try {
CodedInputStream input = CodedInputStream.newInstance(data, off, len);
mergeFrom(input);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a byte array threw an IOException (should " +
"never happen).", e);
if (index != -1) {
result.append('[')
.append(index)
.append(']');
}
result.append('.');
return result.toString();
}
// ===============================================================
// The following definitions seem to be required in order to make javac
// not produce weird errors like:
//
// java/com/google/protobuf/DynamicMessage.java:203: types
// com.google.protobuf.AbstractMessage.Builder<
// com.google.protobuf.DynamicMessage.Builder> and
// com.google.protobuf.AbstractMessage.Builder<
// com.google.protobuf.DynamicMessage.Builder> are incompatible; both
// define mergeFrom(com.google.protobuf.ByteString), but with unrelated
// return types.
//
// Strangely, these lines are only needed if javac is invoked separately
// on AbstractMessage.java and AbstractMessageLite.java. If javac is
// invoked on both simultaneously, it works. (Or maybe the important
// point is whether or not DynamicMessage.java is compiled together with
// AbstractMessageLite.java -- not sure.) I suspect this is a compiler
// bug.
@Override
public BuilderType mergeFrom(final ByteString data)
throws InvalidProtocolBufferException {
return super.mergeFrom(data);
}
@Override
public BuilderType mergeFrom(
byte[] data,
ExtensionRegistry extensionRegistry)
final ByteString data,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return mergeFrom(data, 0, data.length, extensionRegistry);
return super.mergeFrom(data, extensionRegistry);
}
@Override
public BuilderType mergeFrom(final byte[] data)
throws InvalidProtocolBufferException {
return super.mergeFrom(data);
}
@Override
public BuilderType mergeFrom(
byte[] data, int off, int len,
ExtensionRegistry extensionRegistry)
final byte[] data, final int off, final int len)
throws InvalidProtocolBufferException {
try {
CodedInputStream input = CodedInputStream.newInstance(data, off, len);
mergeFrom(input, extensionRegistry);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a byte array threw an IOException (should " +
"never happen).", e);
}
return super.mergeFrom(data, off, len);
}
public BuilderType mergeFrom(InputStream input) throws IOException {
CodedInputStream codedInput = CodedInputStream.newInstance(input);
mergeFrom(codedInput);
codedInput.checkLastTagWas(0);
return (BuilderType) this;
@Override
public BuilderType mergeFrom(
final byte[] data,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return super.mergeFrom(data, extensionRegistry);
}
public BuilderType mergeFrom(InputStream input,
ExtensionRegistry extensionRegistry)
throws IOException {
CodedInputStream codedInput = CodedInputStream.newInstance(input);
mergeFrom(codedInput, extensionRegistry);
codedInput.checkLastTagWas(0);
return (BuilderType) this;
@Override
public BuilderType mergeFrom(
final byte[] data, final int off, final int len,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return super.mergeFrom(data, off, len, extensionRegistry);
}
public BuilderType mergeDelimitedFrom(InputStream input,
ExtensionRegistry extensionRegistry)
throws IOException {
final int size = CodedInputStream.readRawVarint32(input);
// A stream which will not read more than |size| bytes.
InputStream limitedInput = new FilterInputStream(input) {
int limit = size;
@Override
public int available() throws IOException {
return Math.min(super.available(), limit);
}
@Override
public int read() throws IOException {
if (limit <= 0) return -1;
int result = super.read();
if (result >= 0) --limit;
return result;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (limit <= 0) return -1;
len = Math.min(len, limit);
int result = super.read(b, off, len);
if (result >= 0) limit -= result;
return result;
}
@Override
public long skip(long n) throws IOException {
long result = super.skip(Math.min(n, limit));
if (result >= 0) limit -= result;
return result;
}
};
return mergeFrom(limitedInput, extensionRegistry);
}
public BuilderType mergeDelimitedFrom(InputStream input)
@Override
public BuilderType mergeFrom(final InputStream input)
throws IOException {
return mergeDelimitedFrom(input, ExtensionRegistry.getEmptyRegistry());
return super.mergeFrom(input);
}
@Override
public BuilderType mergeFrom(
final InputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
return super.mergeFrom(input, extensionRegistry);
}
@Override
public BuilderType mergeDelimitedFrom(final InputStream input)
throws IOException {
return super.mergeDelimitedFrom(input);
}
@Override
public BuilderType mergeDelimitedFrom(
final InputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
return super.mergeDelimitedFrom(input, extensionRegistry);
}
}
}

View File

@ -0,0 +1,321 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.FilterInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
/**
* A partial implementation of the {@link MessageLite} interface which
* implements as many methods of that interface as possible in terms of other
* methods.
*
* @author kenton@google.com Kenton Varda
*/
public abstract class AbstractMessageLite implements MessageLite {
public ByteString toByteString() {
try {
final ByteString.CodedBuilder out =
ByteString.newCodedBuilder(getSerializedSize());
writeTo(out.getCodedOutput());
return out.build();
} catch (IOException e) {
throw new RuntimeException(
"Serializing to a ByteString threw an IOException (should " +
"never happen).", e);
}
}
public byte[] toByteArray() {
try {
final byte[] result = new byte[getSerializedSize()];
final CodedOutputStream output = CodedOutputStream.newInstance(result);
writeTo(output);
output.checkNoSpaceLeft();
return result;
} catch (IOException e) {
throw new RuntimeException(
"Serializing to a byte array threw an IOException " +
"(should never happen).", e);
}
}
public void writeTo(final OutputStream output) throws IOException {
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
writeTo(codedOutput);
codedOutput.flush();
}
public void writeDelimitedTo(final OutputStream output) throws IOException {
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
codedOutput.writeRawVarint32(getSerializedSize());
writeTo(codedOutput);
codedOutput.flush();
}
/**
* A partial implementation of the {@link Message.Builder} interface which
* implements as many methods of that interface as possible in terms of
* other methods.
*/
@SuppressWarnings("unchecked")
public static abstract class Builder<BuilderType extends Builder>
implements MessageLite.Builder {
// The compiler produces an error if this is not declared explicitly.
@Override
public abstract BuilderType clone();
public BuilderType mergeFrom(final CodedInputStream input)
throws IOException {
// TODO(kenton): Don't use null here. Currently we have to because
// using ExtensionRegistry.getEmptyRegistry() would imply a dependency
// on ExtensionRegistry. However, AbstractMessage overrides this with
// a correct implementation, and lite messages don't yet support
// extensions, so it ends up not mattering for now. It will matter
// once lite messages support extensions.
return mergeFrom(input, null);
}
// Re-defined here for return type covariance.
public abstract BuilderType mergeFrom(
final CodedInputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException;
public BuilderType mergeFrom(final ByteString data)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input = data.newCodedInput();
mergeFrom(input);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a ByteString threw an IOException (should " +
"never happen).", e);
}
}
public BuilderType mergeFrom(
final ByteString data,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input = data.newCodedInput();
mergeFrom(input, extensionRegistry);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a ByteString threw an IOException (should " +
"never happen).", e);
}
}
public BuilderType mergeFrom(final byte[] data)
throws InvalidProtocolBufferException {
return mergeFrom(data, 0, data.length);
}
public BuilderType mergeFrom(final byte[] data, final int off,
final int len)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input =
CodedInputStream.newInstance(data, off, len);
mergeFrom(input);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a byte array threw an IOException (should " +
"never happen).", e);
}
}
public BuilderType mergeFrom(
final byte[] data,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return mergeFrom(data, 0, data.length, extensionRegistry);
}
public BuilderType mergeFrom(
final byte[] data, final int off, final int len,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input =
CodedInputStream.newInstance(data, off, len);
mergeFrom(input, extensionRegistry);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a byte array threw an IOException (should " +
"never happen).", e);
}
}
public BuilderType mergeFrom(final InputStream input) throws IOException {
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
mergeFrom(codedInput);
codedInput.checkLastTagWas(0);
return (BuilderType) this;
}
public BuilderType mergeFrom(
final InputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
mergeFrom(codedInput, extensionRegistry);
codedInput.checkLastTagWas(0);
return (BuilderType) this;
}
/**
* An InputStream implementations which reads from some other InputStream
* but is limited to a particular number of bytes. Used by
* mergeDelimitedFrom(). This is intentionally package-private so that
* UnknownFieldSet can share it.
*/
static final class LimitedInputStream extends FilterInputStream {
private int limit;
LimitedInputStream(InputStream in, int limit) {
super(in);
this.limit = limit;
}
@Override
public int available() throws IOException {
return Math.min(super.available(), limit);
}
@Override
public int read() throws IOException {
if (limit <= 0) {
return -1;
}
final int result = super.read();
if (result >= 0) {
--limit;
}
return result;
}
@Override
public int read(final byte[] b, final int off, int len)
throws IOException {
if (limit <= 0) {
return -1;
}
len = Math.min(len, limit);
final int result = super.read(b, off, len);
if (result >= 0) {
limit -= result;
}
return result;
}
@Override
public long skip(final long n) throws IOException {
final long result = super.skip(Math.min(n, limit));
if (result >= 0) {
limit -= result;
}
return result;
}
}
public BuilderType mergeDelimitedFrom(
final InputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
final int size = CodedInputStream.readRawVarint32(input);
final InputStream limitedInput = new LimitedInputStream(input, size);
return mergeFrom(limitedInput, extensionRegistry);
}
public BuilderType mergeDelimitedFrom(final InputStream input)
throws IOException {
final int size = CodedInputStream.readRawVarint32(input);
final InputStream limitedInput = new LimitedInputStream(input, size);
return mergeFrom(limitedInput);
}
/**
* Construct an UninitializedMessageException reporting missing fields in
* the given message.
*/
protected static UninitializedMessageException
newUninitializedMessageException(MessageLite message) {
return new UninitializedMessageException(message);
}
/**
* Adds the {@code values} to the {@code list}. This is a helper method
* used by generated code. Users should ignore it.
*
* @throws NullPointerException if any of the elements of {@code values} is
* null.
*/
protected static <T> void addAll(final Iterable<T> values,
final Collection<? super T> list) {
for (final T value : values) {
if (value == null) {
throw new NullPointerException();
}
}
if (values instanceof Collection) {
@SuppressWarnings("unsafe") final
Collection<T> collection = (Collection<T>) values;
list.addAll(collection);
} else {
for (final T value : values) {
list.add(value);
}
}
}
}
}

View File

@ -46,7 +46,7 @@ import java.nio.ByteBuffer;
public final class ByteString {
private final byte[] bytes;
private ByteString(byte[] bytes) {
private ByteString(final byte[] bytes) {
this.bytes = bytes;
}
@ -55,7 +55,7 @@ public final class ByteString {
*
* @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
*/
public byte byteAt(int index) {
public byte byteAt(final int index) {
return bytes[index];
}
@ -63,14 +63,14 @@ public final class ByteString {
* Gets the number of bytes.
*/
public int size() {
return this.bytes.length;
return bytes.length;
}
/**
* Returns {@code true} if the size is {@code 0}, {@code false} otherwise.
*/
public boolean isEmpty() {
return this.bytes.length == 0;
return bytes.length == 0;
}
// =================================================================
@ -84,8 +84,9 @@ public final class ByteString {
/**
* Copies the given bytes into a {@code ByteString}.
*/
public static ByteString copyFrom(byte[] bytes, int offset, int size) {
byte[] copy = new byte[size];
public static ByteString copyFrom(final byte[] bytes, final int offset,
final int size) {
final byte[] copy = new byte[size];
System.arraycopy(bytes, offset, copy, 0, size);
return new ByteString(copy);
}
@ -93,7 +94,7 @@ public final class ByteString {
/**
* Copies the given bytes into a {@code ByteString}.
*/
public static ByteString copyFrom(byte[] bytes) {
public static ByteString copyFrom(final byte[] bytes) {
return copyFrom(bytes, 0, bytes.length);
}
@ -101,7 +102,7 @@ public final class ByteString {
* Encodes {@code text} into a sequence of bytes using the named charset
* and returns the result as a {@code ByteString}.
*/
public static ByteString copyFrom(String text, String charsetName)
public static ByteString copyFrom(final String text, final String charsetName)
throws UnsupportedEncodingException {
return new ByteString(text.getBytes(charsetName));
}
@ -110,7 +111,7 @@ public final class ByteString {
* Encodes {@code text} into a sequence of UTF-8 bytes and returns the
* result as a {@code ByteString}.
*/
public static ByteString copyFromUtf8(String text) {
public static ByteString copyFromUtf8(final String text) {
try {
return new ByteString(text.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
@ -127,7 +128,7 @@ public final class ByteString {
* @param target buffer to copy into
* @param offset in the target buffer
*/
public void copyTo(byte[] target, int offset) {
public void copyTo(final byte[] target, final int offset) {
System.arraycopy(bytes, 0, target, offset, bytes.length);
}
@ -139,8 +140,9 @@ public final class ByteString {
* @param targetOffset offset within the target buffer
* @param size number of bytes to copy
*/
public void copyTo(byte[] target, int sourceOffset, int targetOffset,
int size) {
public void copyTo(final byte[] target, final int sourceOffset,
final int targetOffset,
final int size) {
System.arraycopy(bytes, sourceOffset, target, targetOffset, size);
}
@ -148,9 +150,9 @@ public final class ByteString {
* Copies bytes to a {@code byte[]}.
*/
public byte[] toByteArray() {
int size = this.bytes.length;
byte[] copy = new byte[size];
System.arraycopy(this.bytes, 0, copy, 0, size);
final int size = bytes.length;
final byte[] copy = new byte[size];
System.arraycopy(bytes, 0, copy, 0, size);
return copy;
}
@ -159,7 +161,7 @@ public final class ByteString {
* same backing byte array.
*/
public ByteBuffer asReadOnlyByteBuffer() {
ByteBuffer byteBuffer = ByteBuffer.wrap(this.bytes);
final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
return byteBuffer.asReadOnlyBuffer();
}
@ -167,9 +169,9 @@ public final class ByteString {
* Constructs a new {@code String} by decoding the bytes using the
* specified charset.
*/
public String toString(String charsetName)
public String toString(final String charsetName)
throws UnsupportedEncodingException {
return new String(this.bytes, charsetName);
return new String(bytes, charsetName);
}
/**
@ -177,7 +179,7 @@ public final class ByteString {
*/
public String toStringUtf8() {
try {
return new String(this.bytes, "UTF-8");
return new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("UTF-8 not supported?", e);
}
@ -187,7 +189,7 @@ public final class ByteString {
// equals() and hashCode()
@Override
public boolean equals(Object o) {
public boolean equals(final Object o) {
if (o == this) {
return true;
}
@ -196,16 +198,16 @@ public final class ByteString {
return false;
}
ByteString other = (ByteString) o;
int size = this.bytes.length;
final ByteString other = (ByteString) o;
final int size = bytes.length;
if (size != other.bytes.length) {
return false;
}
byte[] bytes = this.bytes;
byte[] otherBytes = other.bytes;
final byte[] thisBytes = bytes;
final byte[] otherBytes = other.bytes;
for (int i = 0; i < size; i++) {
if (bytes[i] != otherBytes[i]) {
if (thisBytes[i] != otherBytes[i]) {
return false;
}
}
@ -213,25 +215,25 @@ public final class ByteString {
return true;
}
volatile int hash = 0;
private volatile int hash = 0;
@Override
public int hashCode() {
int h = this.hash;
int h = hash;
if (h == 0) {
byte[] bytes = this.bytes;
int size = this.bytes.length;
final byte[] thisBytes = bytes;
final int size = bytes.length;
h = size;
for (int i = 0; i < size; i++) {
h = h * 31 + bytes[i];
h = h * 31 + thisBytes[i];
}
if (h == 0) {
h = 1;
}
this.hash = h;
hash = h;
}
return h;
@ -264,7 +266,7 @@ public final class ByteString {
/**
* Creates a new {@link Output} with the given initial capacity.
*/
public static Output newOutput(int initialCapacity) {
public static Output newOutput(final int initialCapacity) {
return new Output(new ByteArrayOutputStream(initialCapacity));
}
@ -285,7 +287,7 @@ public final class ByteString {
/**
* Constructs a new output with the given initial capacity.
*/
private Output(ByteArrayOutputStream bout) {
private Output(final ByteArrayOutputStream bout) {
super(bout);
this.bout = bout;
}
@ -294,14 +296,14 @@ public final class ByteString {
* Creates a {@code ByteString} instance from this {@code Output}.
*/
public ByteString toByteString() {
byte[] byteArray = bout.toByteArray();
final byte[] byteArray = bout.toByteArray();
return new ByteString(byteArray);
}
}
/**
* Constructs a new ByteString builder, which allows you to efficiently
* construct a {@code ByteString} by writing to a {@link CodedOutputSteam}.
* construct a {@code ByteString} by writing to a {@link CodedOutputStream}.
* Using this is much more efficient than calling {@code newOutput()} and
* wrapping that in a {@code CodedOutputStream}.
*
@ -312,7 +314,7 @@ public final class ByteString {
* @param size The target byte size of the {@code ByteString}. You must
* write exactly this many bytes before building the result.
*/
static CodedBuilder newCodedBuilder(int size) {
static CodedBuilder newCodedBuilder(final int size) {
return new CodedBuilder(size);
}
@ -321,7 +323,7 @@ public final class ByteString {
private final CodedOutputStream output;
private final byte[] buffer;
private CodedBuilder(int size) {
private CodedBuilder(final int size) {
buffer = new byte[size];
output = CodedOutputStream.newInstance(buffer);
}

View File

@ -51,21 +51,22 @@ public final class CodedInputStream {
/**
* Create a new CodedInputStream wrapping the given InputStream.
*/
public static CodedInputStream newInstance(InputStream input) {
public static CodedInputStream newInstance(final InputStream input) {
return new CodedInputStream(input);
}
/**
* Create a new CodedInputStream wrapping the given byte array.
*/
public static CodedInputStream newInstance(byte[] buf) {
public static CodedInputStream newInstance(final byte[] buf) {
return newInstance(buf, 0, buf.length);
}
/**
* Create a new CodedInputStream wrapping the given byte array slice.
*/
public static CodedInputStream newInstance(byte[] buf, int off, int len) {
public static CodedInputStream newInstance(final byte[] buf, final int off,
final int len) {
return new CodedInputStream(buf, off, len);
}
@ -98,7 +99,8 @@ public final class CodedInputStream {
* @throws InvalidProtocolBufferException {@code value} does not match the
* last tag.
*/
public void checkLastTagWas(int value) throws InvalidProtocolBufferException {
public void checkLastTagWas(final int value)
throws InvalidProtocolBufferException {
if (lastTag != value) {
throw InvalidProtocolBufferException.invalidEndTag();
}
@ -110,7 +112,7 @@ public final class CodedInputStream {
* @return {@code false} if the tag is an endgroup tag, in which case
* nothing is skipped. Otherwise, returns {@code true}.
*/
public boolean skipField(int tag) throws IOException {
public boolean skipField(final int tag) throws IOException {
switch (WireFormat.getTagWireType(tag)) {
case WireFormat.WIRETYPE_VARINT:
readInt32();
@ -143,8 +145,10 @@ public final class CodedInputStream {
*/
public void skipMessage() throws IOException {
while (true) {
int tag = readTag();
if (tag == 0 || !skipField(tag)) return;
final int tag = readTag();
if (tag == 0 || !skipField(tag)) {
return;
}
}
}
@ -192,11 +196,11 @@ public final class CodedInputStream {
/** Read a {@code string} field value from the stream. */
public String readString() throws IOException {
int size = readRawVarint32();
final int size = readRawVarint32();
if (size <= (bufferSize - bufferPos) && size > 0) {
// Fast path: We already have the bytes in a contiguous buffer, so
// just copy directly from it.
String result = new String(buffer, bufferPos, size, "UTF-8");
final String result = new String(buffer, bufferPos, size, "UTF-8");
bufferPos += size;
return result;
} else {
@ -206,8 +210,9 @@ public final class CodedInputStream {
}
/** Read a {@code group} field value from the stream. */
public void readGroup(int fieldNumber, Message.Builder builder,
ExtensionRegistry extensionRegistry)
public void readGroup(final int fieldNumber,
final MessageLite.Builder builder,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
if (recursionDepth >= recursionLimit) {
throw InvalidProtocolBufferException.recursionLimitExceeded();
@ -222,28 +227,31 @@ public final class CodedInputStream {
/**
* Reads a {@code group} field value from the stream and merges it into the
* given {@link UnknownFieldSet}.
*
* @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so
* you can just call {@link #readGroup}.
*/
public void readUnknownGroup(int fieldNumber, UnknownFieldSet.Builder builder)
@Deprecated
public void readUnknownGroup(final int fieldNumber,
final MessageLite.Builder builder)
throws IOException {
if (recursionDepth >= recursionLimit) {
throw InvalidProtocolBufferException.recursionLimitExceeded();
}
++recursionDepth;
builder.mergeFrom(this);
checkLastTagWas(
WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
--recursionDepth;
// We know that UnknownFieldSet will ignore any ExtensionRegistry so it
// is safe to pass null here. (We can't call
// ExtensionRegistry.getEmptyRegistry() because that would make this
// class depend on ExtensionRegistry, which is not part of the lite
// library.)
readGroup(fieldNumber, builder, null);
}
/** Read an embedded message field value from the stream. */
public void readMessage(Message.Builder builder,
ExtensionRegistry extensionRegistry)
public void readMessage(final MessageLite.Builder builder,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
int length = readRawVarint32();
final int length = readRawVarint32();
if (recursionDepth >= recursionLimit) {
throw InvalidProtocolBufferException.recursionLimitExceeded();
}
int oldLimit = pushLimit(length);
final int oldLimit = pushLimit(length);
++recursionDepth;
builder.mergeFrom(this, extensionRegistry);
checkLastTagWas(0);
@ -253,11 +261,11 @@ public final class CodedInputStream {
/** Read a {@code bytes} field value from the stream. */
public ByteString readBytes() throws IOException {
int size = readRawVarint32();
if (size < bufferSize - bufferPos && size > 0) {
final int size = readRawVarint32();
if (size <= (bufferSize - bufferPos) && size > 0) {
// Fast path: We already have the bytes in a contiguous buffer, so
// just copy directly from it.
ByteString result = ByteString.copyFrom(buffer, bufferPos, size);
final ByteString result = ByteString.copyFrom(buffer, bufferPos, size);
bufferPos += size;
return result;
} else {
@ -299,52 +307,6 @@ public final class CodedInputStream {
return decodeZigZag64(readRawVarint64());
}
/**
* Read a field of any primitive type. Enums, groups, and embedded
* messages are not handled by this method.
*
* @param type Declared type of the field.
* @return An object representing the field's value, of the exact
* type which would be returned by
* {@link Message#getField(Descriptors.FieldDescriptor)} for
* this field.
*/
public Object readPrimitiveField(
Descriptors.FieldDescriptor.Type type) throws IOException {
switch (type) {
case DOUBLE : return readDouble ();
case FLOAT : return readFloat ();
case INT64 : return readInt64 ();
case UINT64 : return readUInt64 ();
case INT32 : return readInt32 ();
case FIXED64 : return readFixed64 ();
case FIXED32 : return readFixed32 ();
case BOOL : return readBool ();
case STRING : return readString ();
case BYTES : return readBytes ();
case UINT32 : return readUInt32 ();
case SFIXED32: return readSFixed32();
case SFIXED64: return readSFixed64();
case SINT32 : return readSInt32 ();
case SINT64 : return readSInt64 ();
case GROUP:
throw new IllegalArgumentException(
"readPrimitiveField() cannot handle nested groups.");
case MESSAGE:
throw new IllegalArgumentException(
"readPrimitiveField() cannot handle embedded messages.");
case ENUM:
// We don't hanlde enums because we don't know what to do if the
// value is not recognized.
throw new IllegalArgumentException(
"readPrimitiveField() cannot handle enums.");
}
throw new RuntimeException(
"There is no way to get here, but the compiler thinks otherwise.");
}
// =================================================================
/**
@ -373,7 +335,9 @@ public final class CodedInputStream {
if (tmp < 0) {
// Discard upper 32 bits.
for (int i = 0; i < 5; i++) {
if (readRawByte() >= 0) return result;
if (readRawByte() >= 0) {
return result;
}
}
throw InvalidProtocolBufferException.malformedVarint();
}
@ -390,11 +354,11 @@ public final class CodedInputStream {
* then you would probably end up reading past the end of the varint since
* CodedInputStream buffers its input.
*/
static int readRawVarint32(InputStream input) throws IOException {
static int readRawVarint32(final InputStream input) throws IOException {
int result = 0;
int offset = 0;
for (; offset < 32; offset += 7) {
int b = input.read();
final int b = input.read();
if (b == -1) {
throw InvalidProtocolBufferException.truncatedMessage();
}
@ -405,7 +369,7 @@ public final class CodedInputStream {
}
// Keep reading up to 64 bits.
for (; offset < 64; offset += 7) {
int b = input.read();
final int b = input.read();
if (b == -1) {
throw InvalidProtocolBufferException.truncatedMessage();
}
@ -421,9 +385,11 @@ public final class CodedInputStream {
int shift = 0;
long result = 0;
while (shift < 64) {
byte b = readRawByte();
final byte b = readRawByte();
result |= (long)(b & 0x7F) << shift;
if ((b & 0x80) == 0) return result;
if ((b & 0x80) == 0) {
return result;
}
shift += 7;
}
throw InvalidProtocolBufferException.malformedVarint();
@ -431,10 +397,10 @@ public final class CodedInputStream {
/** Read a 32-bit little-endian integer from the stream. */
public int readRawLittleEndian32() throws IOException {
byte b1 = readRawByte();
byte b2 = readRawByte();
byte b3 = readRawByte();
byte b4 = readRawByte();
final byte b1 = readRawByte();
final byte b2 = readRawByte();
final byte b3 = readRawByte();
final byte b4 = readRawByte();
return (((int)b1 & 0xff) ) |
(((int)b2 & 0xff) << 8) |
(((int)b3 & 0xff) << 16) |
@ -443,14 +409,14 @@ public final class CodedInputStream {
/** Read a 64-bit little-endian integer from the stream. */
public long readRawLittleEndian64() throws IOException {
byte b1 = readRawByte();
byte b2 = readRawByte();
byte b3 = readRawByte();
byte b4 = readRawByte();
byte b5 = readRawByte();
byte b6 = readRawByte();
byte b7 = readRawByte();
byte b8 = readRawByte();
final byte b1 = readRawByte();
final byte b2 = readRawByte();
final byte b3 = readRawByte();
final byte b4 = readRawByte();
final byte b5 = readRawByte();
final byte b6 = readRawByte();
final byte b7 = readRawByte();
final byte b8 = readRawByte();
return (((long)b1 & 0xff) ) |
(((long)b2 & 0xff) << 8) |
(((long)b3 & 0xff) << 16) |
@ -471,7 +437,7 @@ public final class CodedInputStream {
* Java has no explicit unsigned support.
* @return A signed 32-bit integer.
*/
public static int decodeZigZag32(int n) {
public static int decodeZigZag32(final int n) {
return (n >>> 1) ^ -(n & 1);
}
@ -485,31 +451,31 @@ public final class CodedInputStream {
* Java has no explicit unsigned support.
* @return A signed 64-bit integer.
*/
public static long decodeZigZag64(long n) {
public static long decodeZigZag64(final long n) {
return (n >>> 1) ^ -(n & 1);
}
// -----------------------------------------------------------------
private byte[] buffer;
private final byte[] buffer;
private int bufferSize;
private int bufferSizeAfterLimit = 0;
private int bufferSizeAfterLimit;
private int bufferPos;
private InputStream input;
private int lastTag = 0;
private final InputStream input;
private int lastTag;
/**
* The total number of bytes read before the current buffer. The total
* bytes read up to the current position can be computed as
* {@code totalBytesRetired + bufferPos}.
*/
private int totalBytesRetired = 0;
private int totalBytesRetired;
/** The absolute position of the end of the current message. */
private int currentLimit = Integer.MAX_VALUE;
/** See setRecursionLimit() */
private int recursionDepth = 0;
private int recursionDepth;
private int recursionLimit = DEFAULT_RECURSION_LIMIT;
/** See setSizeLimit() */
@ -519,17 +485,17 @@ public final class CodedInputStream {
private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB
private static final int BUFFER_SIZE = 4096;
private CodedInputStream(byte[] buffer, int off, int len) {
private CodedInputStream(final byte[] buffer, final int off, final int len) {
this.buffer = buffer;
this.bufferSize = off + len;
this.bufferPos = off;
this.input = null;
bufferSize = off + len;
bufferPos = off;
input = null;
}
private CodedInputStream(InputStream input) {
this.buffer = new byte[BUFFER_SIZE];
this.bufferSize = 0;
this.bufferPos = 0;
private CodedInputStream(final InputStream input) {
buffer = new byte[BUFFER_SIZE];
bufferSize = 0;
bufferPos = 0;
this.input = input;
}
@ -540,12 +506,12 @@ public final class CodedInputStream {
*
* @return the old limit.
*/
public int setRecursionLimit(int limit) {
public int setRecursionLimit(final int limit) {
if (limit < 0) {
throw new IllegalArgumentException(
"Recursion limit cannot be negative: " + limit);
}
int oldLimit = recursionLimit;
final int oldLimit = recursionLimit;
recursionLimit = limit;
return oldLimit;
}
@ -566,12 +532,12 @@ public final class CodedInputStream {
*
* @return the old limit.
*/
public int setSizeLimit(int limit) {
public int setSizeLimit(final int limit) {
if (limit < 0) {
throw new IllegalArgumentException(
"Size limit cannot be negative: " + limit);
}
int oldLimit = sizeLimit;
final int oldLimit = sizeLimit;
sizeLimit = limit;
return oldLimit;
}
@ -594,7 +560,7 @@ public final class CodedInputStream {
throw InvalidProtocolBufferException.negativeSize();
}
byteLimit += totalBytesRetired + bufferPos;
int oldLimit = currentLimit;
final int oldLimit = currentLimit;
if (byteLimit > oldLimit) {
throw InvalidProtocolBufferException.truncatedMessage();
}
@ -607,7 +573,7 @@ public final class CodedInputStream {
private void recomputeBufferSizeAfterLimit() {
bufferSize += bufferSizeAfterLimit;
int bufferEnd = totalBytesRetired + bufferSize;
final int bufferEnd = totalBytesRetired + bufferSize;
if (bufferEnd > currentLimit) {
// Limit is in current buffer.
bufferSizeAfterLimit = bufferEnd - currentLimit;
@ -622,7 +588,7 @@ public final class CodedInputStream {
*
* @param oldLimit The old limit, as returned by {@code pushLimit}.
*/
public void popLimit(int oldLimit) {
public void popLimit(final int oldLimit) {
currentLimit = oldLimit;
recomputeBufferSizeAfterLimit();
}
@ -636,7 +602,7 @@ public final class CodedInputStream {
return -1;
}
int currentAbsolutePosition = totalBytesRetired + bufferPos;
final int currentAbsolutePosition = totalBytesRetired + bufferPos;
return currentLimit - currentAbsolutePosition;
}
@ -656,7 +622,7 @@ public final class CodedInputStream {
* or it will throw an exception. If {@code mustSucceed} is false,
* refillBuffer() returns false if no more bytes were available.
*/
private boolean refillBuffer(boolean mustSucceed) throws IOException {
private boolean refillBuffer(final boolean mustSucceed) throws IOException {
if (bufferPos < bufferSize) {
throw new IllegalStateException(
"refillBuffer() called when buffer wasn't empty.");
@ -689,7 +655,7 @@ public final class CodedInputStream {
}
} else {
recomputeBufferSizeAfterLimit();
int totalBytesRead =
final int totalBytesRead =
totalBytesRetired + bufferSize + bufferSizeAfterLimit;
if (totalBytesRead > sizeLimit || totalBytesRead < 0) {
throw InvalidProtocolBufferException.sizeLimitExceeded();
@ -717,7 +683,7 @@ public final class CodedInputStream {
* @throws InvalidProtocolBufferException The end of the stream or the current
* limit was reached.
*/
public byte[] readRawBytes(int size) throws IOException {
public byte[] readRawBytes(final int size) throws IOException {
if (size < 0) {
throw InvalidProtocolBufferException.negativeSize();
}
@ -731,7 +697,7 @@ public final class CodedInputStream {
if (size <= bufferSize - bufferPos) {
// We have all the bytes we need already.
byte[] bytes = new byte[size];
final byte[] bytes = new byte[size];
System.arraycopy(buffer, bufferPos, bytes, 0, size);
bufferPos += size;
return bytes;
@ -740,7 +706,7 @@ public final class CodedInputStream {
// of bytes. We can safely allocate the resulting array ahead of time.
// First copy what we have.
byte[] bytes = new byte[size];
final byte[] bytes = new byte[size];
int pos = bufferSize - bufferPos;
System.arraycopy(buffer, bufferPos, bytes, 0, pos);
bufferPos = bufferSize;
@ -772,8 +738,8 @@ public final class CodedInputStream {
// Remember the buffer markers since we'll have to copy the bytes out of
// it later.
int originalBufferPos = bufferPos;
int originalBufferSize = bufferSize;
final int originalBufferPos = bufferPos;
final int originalBufferSize = bufferSize;
// Mark the current buffer consumed.
totalBytesRetired += bufferSize;
@ -782,13 +748,13 @@ public final class CodedInputStream {
// Read all the rest of the bytes we need.
int sizeLeft = size - (originalBufferSize - originalBufferPos);
List<byte[]> chunks = new ArrayList<byte[]>();
final List<byte[]> chunks = new ArrayList<byte[]>();
while (sizeLeft > 0) {
byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
int pos = 0;
while (pos < chunk.length) {
int n = (input == null) ? -1 :
final int n = (input == null) ? -1 :
input.read(chunk, pos, chunk.length - pos);
if (n == -1) {
throw InvalidProtocolBufferException.truncatedMessage();
@ -801,14 +767,14 @@ public final class CodedInputStream {
}
// OK, got everything. Now concatenate it all into one buffer.
byte[] bytes = new byte[size];
final byte[] bytes = new byte[size];
// Start by copying the leftover bytes from this.buffer.
int pos = originalBufferSize - originalBufferPos;
System.arraycopy(buffer, originalBufferPos, bytes, 0, pos);
// And now all the chunks.
for (byte[] chunk : chunks) {
for (final byte[] chunk : chunks) {
System.arraycopy(chunk, 0, bytes, pos, chunk.length);
pos += chunk.length;
}
@ -824,7 +790,7 @@ public final class CodedInputStream {
* @throws InvalidProtocolBufferException The end of the stream or the current
* limit was reached.
*/
public void skipRawBytes(int size) throws IOException {
public void skipRawBytes(final int size) throws IOException {
if (size < 0) {
throw InvalidProtocolBufferException.negativeSize();
}
@ -848,7 +814,7 @@ public final class CodedInputStream {
// Then skip directly from the InputStream for the rest.
while (pos < size) {
int n = (input == null) ? -1 : (int) input.skip(size - pos);
final int n = (input == null) ? -1 : (int) input.skip(size - pos);
if (n <= 0) {
throw InvalidProtocolBufferException.truncatedMessage();
}

View File

@ -32,6 +32,7 @@ package com.google.protobuf;
import java.io.OutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
/**
* Encodes and writes protocol message fields.
@ -55,29 +56,30 @@ public final class CodedOutputStream {
private final OutputStream output;
/**
* The buffer size used in {@link #newInstance(java.io.OutputStream)}.
* The buffer size used in {@link #newInstance(OutputStream)}.
*/
public static final int DEFAULT_BUFFER_SIZE = 4096;
private CodedOutputStream(byte[] buffer, int offset, int length) {
this.output = null;
private CodedOutputStream(final byte[] buffer, final int offset,
final int length) {
output = null;
this.buffer = buffer;
this.position = offset;
this.limit = offset + length;
position = offset;
limit = offset + length;
}
private CodedOutputStream(OutputStream output, byte[] buffer) {
private CodedOutputStream(final OutputStream output, final byte[] buffer) {
this.output = output;
this.buffer = buffer;
this.position = 0;
this.limit = buffer.length;
position = 0;
limit = buffer.length;
}
/**
* Create a new {@code CodedOutputStream} wrapping the given
* {@code OutputStream}.
*/
public static CodedOutputStream newInstance(OutputStream output) {
public static CodedOutputStream newInstance(final OutputStream output) {
return newInstance(output, DEFAULT_BUFFER_SIZE);
}
@ -85,8 +87,8 @@ public final class CodedOutputStream {
* Create a new {@code CodedOutputStream} wrapping the given
* {@code OutputStream} with a given buffer size.
*/
public static CodedOutputStream newInstance(OutputStream output,
int bufferSize) {
public static CodedOutputStream newInstance(final OutputStream output,
final int bufferSize) {
return new CodedOutputStream(output, new byte[bufferSize]);
}
@ -97,7 +99,7 @@ public final class CodedOutputStream {
* array is faster than writing to an {@code OutputStream}. See also
* {@link ByteString#newCodedBuilder}.
*/
public static CodedOutputStream newInstance(byte[] flatArray) {
public static CodedOutputStream newInstance(final byte[] flatArray) {
return newInstance(flatArray, 0, flatArray.length);
}
@ -108,96 +110,115 @@ public final class CodedOutputStream {
* array is faster than writing to an {@code OutputStream}. See also
* {@link ByteString#newCodedBuilder}.
*/
public static CodedOutputStream newInstance(byte[] flatArray, int offset,
int length) {
public static CodedOutputStream newInstance(final byte[] flatArray,
final int offset,
final int length) {
return new CodedOutputStream(flatArray, offset, length);
}
// -----------------------------------------------------------------
/** Write a {@code double} field, including tag, to the stream. */
public void writeDouble(int fieldNumber, double value) throws IOException {
public void writeDouble(final int fieldNumber, final double value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
writeDoubleNoTag(value);
}
/** Write a {@code float} field, including tag, to the stream. */
public void writeFloat(int fieldNumber, float value) throws IOException {
public void writeFloat(final int fieldNumber, final float value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
writeFloatNoTag(value);
}
/** Write a {@code uint64} field, including tag, to the stream. */
public void writeUInt64(int fieldNumber, long value) throws IOException {
public void writeUInt64(final int fieldNumber, final long value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
writeUInt64NoTag(value);
}
/** Write an {@code int64} field, including tag, to the stream. */
public void writeInt64(int fieldNumber, long value) throws IOException {
public void writeInt64(final int fieldNumber, final long value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
writeInt64NoTag(value);
}
/** Write an {@code int32} field, including tag, to the stream. */
public void writeInt32(int fieldNumber, int value) throws IOException {
public void writeInt32(final int fieldNumber, final int value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
writeInt32NoTag(value);
}
/** Write a {@code fixed64} field, including tag, to the stream. */
public void writeFixed64(int fieldNumber, long value) throws IOException {
public void writeFixed64(final int fieldNumber, final long value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
writeFixed64NoTag(value);
}
/** Write a {@code fixed32} field, including tag, to the stream. */
public void writeFixed32(int fieldNumber, int value) throws IOException {
public void writeFixed32(final int fieldNumber, final int value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
writeFixed32NoTag(value);
}
/** Write a {@code bool} field, including tag, to the stream. */
public void writeBool(int fieldNumber, boolean value) throws IOException {
public void writeBool(final int fieldNumber, final boolean value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
writeBoolNoTag(value);
}
/** Write a {@code string} field, including tag, to the stream. */
public void writeString(int fieldNumber, String value) throws IOException {
public void writeString(final int fieldNumber, final String value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
writeStringNoTag(value);
}
/** Write a {@code group} field, including tag, to the stream. */
public void writeGroup(int fieldNumber, Message value) throws IOException {
public void writeGroup(final int fieldNumber, final MessageLite value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
writeGroupNoTag(value);
writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
}
/** Write a group represented by an {@link UnknownFieldSet}. */
public void writeUnknownGroup(int fieldNumber, UnknownFieldSet value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
writeUnknownGroupNoTag(value);
writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
/**
* Write a group represented by an {@link UnknownFieldSet}.
*
* @deprecated UnknownFieldSet now implements MessageLite, so you can just
* call {@link #writeGroup}.
*/
@Deprecated
public void writeUnknownGroup(final int fieldNumber,
final MessageLite value)
throws IOException {
writeGroup(fieldNumber, value);
}
/** Write an embedded message field, including tag, to the stream. */
public void writeMessage(int fieldNumber, Message value) throws IOException {
public void writeMessage(final int fieldNumber, final MessageLite value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
writeMessageNoTag(value);
}
/** Write a {@code bytes} field, including tag, to the stream. */
public void writeBytes(int fieldNumber, ByteString value) throws IOException {
public void writeBytes(final int fieldNumber, final ByteString value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
writeBytesNoTag(value);
}
/** Write a {@code uint32} field, including tag, to the stream. */
public void writeUInt32(int fieldNumber, int value) throws IOException {
public void writeUInt32(final int fieldNumber, final int value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
writeUInt32NoTag(value);
}
@ -206,31 +227,36 @@ public final class CodedOutputStream {
* Write an enum field, including tag, to the stream. Caller is responsible
* for converting the enum value to its numeric value.
*/
public void writeEnum(int fieldNumber, int value) throws IOException {
public void writeEnum(final int fieldNumber, final int value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
writeEnumNoTag(value);
}
/** Write an {@code sfixed32} field, including tag, to the stream. */
public void writeSFixed32(int fieldNumber, int value) throws IOException {
public void writeSFixed32(final int fieldNumber, final int value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
writeSFixed32NoTag(value);
}
/** Write an {@code sfixed64} field, including tag, to the stream. */
public void writeSFixed64(int fieldNumber, long value) throws IOException {
public void writeSFixed64(final int fieldNumber, final long value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
writeSFixed64NoTag(value);
}
/** Write an {@code sint32} field, including tag, to the stream. */
public void writeSInt32(int fieldNumber, int value) throws IOException {
public void writeSInt32(final int fieldNumber, final int value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
writeSInt32NoTag(value);
}
/** Write an {@code sint64} field, including tag, to the stream. */
public void writeSInt64(int fieldNumber, long value) throws IOException {
public void writeSInt64(final int fieldNumber, final long value)
throws IOException {
writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
writeSInt64NoTag(value);
}
@ -239,8 +265,9 @@ public final class CodedOutputStream {
* Write a MessageSet extension field to the stream. For historical reasons,
* the wire format differs from normal fields.
*/
public void writeMessageSetExtension(int fieldNumber, Message value)
throws IOException {
public void writeMessageSetExtension(final int fieldNumber,
final MessageLite value)
throws IOException {
writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
@ -251,7 +278,8 @@ public final class CodedOutputStream {
* Write an unparsed MessageSet extension field to the stream. For
* historical reasons, the wire format differs from normal fields.
*/
public void writeRawMessageSetExtension(int fieldNumber, ByteString value)
public void writeRawMessageSetExtension(final int fieldNumber,
final ByteString value)
throws IOException {
writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
@ -259,89 +287,30 @@ public final class CodedOutputStream {
writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
}
/**
* Write a field of arbitrary type, including tag, to the stream.
*
* @param type The field's type.
* @param number The field's number.
* @param value Object representing the field's value. Must be of the exact
* type which would be returned by
* {@link Message#getField(Descriptors.FieldDescriptor)} for
* this field.
*/
public void writeField(Descriptors.FieldDescriptor.Type type,
int number,
Object value) throws IOException {
// Special case for groups, which need a start and end tag; other fields
// can just use writeTag() and writeFieldNoTag().
if (type == Descriptors.FieldDescriptor.Type.GROUP) {
writeGroup(number, (Message) value);
} else {
writeTag(number, WireFormat.getWireFormatForFieldType(type));
writeFieldNoTag(type, value);
}
}
/**
* Write a field of arbitrary type, without its tag, to the stream.
*
* @param type The field's type.
* @param value Object representing the field's value. Must be of the exact
* type which would be returned by
* {@link Message#getField(Descriptors.FieldDescriptor)} for
* this field.
*/
public void writeFieldNoTag(Descriptors.FieldDescriptor.Type type,
Object value) throws IOException {
switch (type) {
case DOUBLE : writeDoubleNoTag ((Double ) value); break;
case FLOAT : writeFloatNoTag ((Float ) value); break;
case INT64 : writeInt64NoTag ((Long ) value); break;
case UINT64 : writeUInt64NoTag ((Long ) value); break;
case INT32 : writeInt32NoTag ((Integer ) value); break;
case FIXED64 : writeFixed64NoTag ((Long ) value); break;
case FIXED32 : writeFixed32NoTag ((Integer ) value); break;
case BOOL : writeBoolNoTag ((Boolean ) value); break;
case STRING : writeStringNoTag ((String ) value); break;
case GROUP : writeGroupNoTag ((Message ) value); break;
case MESSAGE : writeMessageNoTag ((Message ) value); break;
case BYTES : writeBytesNoTag ((ByteString) value); break;
case UINT32 : writeUInt32NoTag ((Integer ) value); break;
case SFIXED32: writeSFixed32NoTag((Integer ) value); break;
case SFIXED64: writeSFixed64NoTag((Long ) value); break;
case SINT32 : writeSInt32NoTag ((Integer ) value); break;
case SINT64 : writeSInt64NoTag ((Long ) value); break;
case ENUM:
writeEnumNoTag(((Descriptors.EnumValueDescriptor) value).getNumber());
break;
}
}
// -----------------------------------------------------------------
/** Write a {@code double} field to the stream. */
public void writeDoubleNoTag(double value) throws IOException {
public void writeDoubleNoTag(final double value) throws IOException {
writeRawLittleEndian64(Double.doubleToRawLongBits(value));
}
/** Write a {@code float} field to the stream. */
public void writeFloatNoTag(float value) throws IOException {
public void writeFloatNoTag(final float value) throws IOException {
writeRawLittleEndian32(Float.floatToRawIntBits(value));
}
/** Write a {@code uint64} field to the stream. */
public void writeUInt64NoTag(long value) throws IOException {
public void writeUInt64NoTag(final long value) throws IOException {
writeRawVarint64(value);
}
/** Write an {@code int64} field to the stream. */
public void writeInt64NoTag(long value) throws IOException {
public void writeInt64NoTag(final long value) throws IOException {
writeRawVarint64(value);
}
/** Write an {@code int32} field to the stream. */
public void writeInt32NoTag(int value) throws IOException {
public void writeInt32NoTag(final int value) throws IOException {
if (value >= 0) {
writeRawVarint32(value);
} else {
@ -351,56 +320,62 @@ public final class CodedOutputStream {
}
/** Write a {@code fixed64} field to the stream. */
public void writeFixed64NoTag(long value) throws IOException {
public void writeFixed64NoTag(final long value) throws IOException {
writeRawLittleEndian64(value);
}
/** Write a {@code fixed32} field to the stream. */
public void writeFixed32NoTag(int value) throws IOException {
public void writeFixed32NoTag(final int value) throws IOException {
writeRawLittleEndian32(value);
}
/** Write a {@code bool} field to the stream. */
public void writeBoolNoTag(boolean value) throws IOException {
public void writeBoolNoTag(final boolean value) throws IOException {
writeRawByte(value ? 1 : 0);
}
/** Write a {@code string} field to the stream. */
public void writeStringNoTag(String value) throws IOException {
public void writeStringNoTag(final String value) throws IOException {
// Unfortunately there does not appear to be any way to tell Java to encode
// UTF-8 directly into our buffer, so we have to let it create its own byte
// array and then copy.
byte[] bytes = value.getBytes("UTF-8");
final byte[] bytes = value.getBytes("UTF-8");
writeRawVarint32(bytes.length);
writeRawBytes(bytes);
}
/** Write a {@code group} field to the stream. */
public void writeGroupNoTag(Message value) throws IOException {
public void writeGroupNoTag(final MessageLite value) throws IOException {
value.writeTo(this);
}
/** Write a group represented by an {@link UnknownFieldSet}. */
public void writeUnknownGroupNoTag(UnknownFieldSet value)
/**
* Write a group represented by an {@link UnknownFieldSet}.
*
* @deprecated UnknownFieldSet now implements MessageLite, so you can just
* call {@link #writeGroupNoTag}.
*/
@Deprecated
public void writeUnknownGroupNoTag(final MessageLite value)
throws IOException {
value.writeTo(this);
writeGroupNoTag(value);
}
/** Write an embedded message field to the stream. */
public void writeMessageNoTag(Message value) throws IOException {
public void writeMessageNoTag(final MessageLite value) throws IOException {
writeRawVarint32(value.getSerializedSize());
value.writeTo(this);
}
/** Write a {@code bytes} field to the stream. */
public void writeBytesNoTag(ByteString value) throws IOException {
byte[] bytes = value.toByteArray();
public void writeBytesNoTag(final ByteString value) throws IOException {
final byte[] bytes = value.toByteArray();
writeRawVarint32(bytes.length);
writeRawBytes(bytes);
}
/** Write a {@code uint32} field to the stream. */
public void writeUInt32NoTag(int value) throws IOException {
public void writeUInt32NoTag(final int value) throws IOException {
writeRawVarint32(value);
}
@ -408,27 +383,27 @@ public final class CodedOutputStream {
* Write an enum field to the stream. Caller is responsible
* for converting the enum value to its numeric value.
*/
public void writeEnumNoTag(int value) throws IOException {
public void writeEnumNoTag(final int value) throws IOException {
writeRawVarint32(value);
}
/** Write an {@code sfixed32} field to the stream. */
public void writeSFixed32NoTag(int value) throws IOException {
public void writeSFixed32NoTag(final int value) throws IOException {
writeRawLittleEndian32(value);
}
/** Write an {@code sfixed64} field to the stream. */
public void writeSFixed64NoTag(long value) throws IOException {
public void writeSFixed64NoTag(final long value) throws IOException {
writeRawLittleEndian64(value);
}
/** Write an {@code sint32} field to the stream. */
public void writeSInt32NoTag(int value) throws IOException {
public void writeSInt32NoTag(final int value) throws IOException {
writeRawVarint32(encodeZigZag32(value));
}
/** Write an {@code sint64} field to the stream. */
public void writeSInt64NoTag(long value) throws IOException {
public void writeSInt64NoTag(final long value) throws IOException {
writeRawVarint64(encodeZigZag64(value));
}
@ -438,7 +413,8 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code double} field, including tag.
*/
public static int computeDoubleSize(int fieldNumber, double value) {
public static int computeDoubleSize(final int fieldNumber,
final double value) {
return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value);
}
@ -446,7 +422,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code float} field, including tag.
*/
public static int computeFloatSize(int fieldNumber, float value) {
public static int computeFloatSize(final int fieldNumber, final float value) {
return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value);
}
@ -454,7 +430,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code uint64} field, including tag.
*/
public static int computeUInt64Size(int fieldNumber, long value) {
public static int computeUInt64Size(final int fieldNumber, final long value) {
return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value);
}
@ -462,7 +438,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode an
* {@code int64} field, including tag.
*/
public static int computeInt64Size(int fieldNumber, long value) {
public static int computeInt64Size(final int fieldNumber, final long value) {
return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value);
}
@ -470,7 +446,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode an
* {@code int32} field, including tag.
*/
public static int computeInt32Size(int fieldNumber, int value) {
public static int computeInt32Size(final int fieldNumber, final int value) {
return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value);
}
@ -478,7 +454,8 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code fixed64} field, including tag.
*/
public static int computeFixed64Size(int fieldNumber, long value) {
public static int computeFixed64Size(final int fieldNumber,
final long value) {
return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value);
}
@ -486,7 +463,8 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code fixed32} field, including tag.
*/
public static int computeFixed32Size(int fieldNumber, int value) {
public static int computeFixed32Size(final int fieldNumber,
final int value) {
return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value);
}
@ -494,7 +472,8 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code bool} field, including tag.
*/
public static int computeBoolSize(int fieldNumber, boolean value) {
public static int computeBoolSize(final int fieldNumber,
final boolean value) {
return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value);
}
@ -502,7 +481,8 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code string} field, including tag.
*/
public static int computeStringSize(int fieldNumber, String value) {
public static int computeStringSize(final int fieldNumber,
final String value) {
return computeTagSize(fieldNumber) + computeStringSizeNoTag(value);
}
@ -510,7 +490,8 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code group} field, including tag.
*/
public static int computeGroupSize(int fieldNumber, Message value) {
public static int computeGroupSize(final int fieldNumber,
final MessageLite value) {
return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
}
@ -518,18 +499,22 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code group} field represented by an {@code UnknownFieldSet}, including
* tag.
*
* @deprecated UnknownFieldSet now implements MessageLite, so you can just
* call {@link #computeGroupSize}.
*/
public static int computeUnknownGroupSize(int fieldNumber,
UnknownFieldSet value) {
return computeTagSize(fieldNumber) * 2 +
computeUnknownGroupSizeNoTag(value);
@Deprecated
public static int computeUnknownGroupSize(final int fieldNumber,
final MessageLite value) {
return computeGroupSize(fieldNumber, value);
}
/**
* Compute the number of bytes that would be needed to encode an
* embedded message field, including tag.
*/
public static int computeMessageSize(int fieldNumber, Message value) {
public static int computeMessageSize(final int fieldNumber,
final MessageLite value) {
return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
}
@ -537,7 +522,8 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code bytes} field, including tag.
*/
public static int computeBytesSize(int fieldNumber, ByteString value) {
public static int computeBytesSize(final int fieldNumber,
final ByteString value) {
return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value);
}
@ -545,7 +531,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code uint32} field, including tag.
*/
public static int computeUInt32Size(int fieldNumber, int value) {
public static int computeUInt32Size(final int fieldNumber, final int value) {
return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value);
}
@ -554,7 +540,7 @@ public final class CodedOutputStream {
* enum field, including tag. Caller is responsible for converting the
* enum value to its numeric value.
*/
public static int computeEnumSize(int fieldNumber, int value) {
public static int computeEnumSize(final int fieldNumber, final int value) {
return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value);
}
@ -562,7 +548,8 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode an
* {@code sfixed32} field, including tag.
*/
public static int computeSFixed32Size(int fieldNumber, int value) {
public static int computeSFixed32Size(final int fieldNumber,
final int value) {
return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value);
}
@ -570,7 +557,8 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode an
* {@code sfixed64} field, including tag.
*/
public static int computeSFixed64Size(int fieldNumber, long value) {
public static int computeSFixed64Size(final int fieldNumber,
final long value) {
return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value);
}
@ -578,7 +566,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode an
* {@code sint32} field, including tag.
*/
public static int computeSInt32Size(int fieldNumber, int value) {
public static int computeSInt32Size(final int fieldNumber, final int value) {
return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value);
}
@ -586,7 +574,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode an
* {@code sint64} field, including tag.
*/
public static int computeSInt64Size(int fieldNumber, long value) {
public static int computeSInt64Size(final int fieldNumber, final long value) {
return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value);
}
@ -596,7 +584,7 @@ public final class CodedOutputStream {
* the wire format differs from normal fields.
*/
public static int computeMessageSetExtensionSize(
int fieldNumber, Message value) {
final int fieldNumber, final MessageLite value) {
return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 +
computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) +
computeMessageSize(WireFormat.MESSAGE_SET_MESSAGE, value);
@ -608,7 +596,7 @@ public final class CodedOutputStream {
* historical reasons, the wire format differs from normal fields.
*/
public static int computeRawMessageSetExtensionSize(
int fieldNumber, ByteString value) {
final int fieldNumber, final ByteString value) {
return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 +
computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) +
computeBytesSize(WireFormat.MESSAGE_SET_MESSAGE, value);
@ -620,7 +608,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code double} field, including tag.
*/
public static int computeDoubleSizeNoTag(double value) {
public static int computeDoubleSizeNoTag(final double value) {
return LITTLE_ENDIAN_64_SIZE;
}
@ -628,7 +616,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code float} field, including tag.
*/
public static int computeFloatSizeNoTag(float value) {
public static int computeFloatSizeNoTag(final float value) {
return LITTLE_ENDIAN_32_SIZE;
}
@ -636,7 +624,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code uint64} field, including tag.
*/
public static int computeUInt64SizeNoTag(long value) {
public static int computeUInt64SizeNoTag(final long value) {
return computeRawVarint64Size(value);
}
@ -644,7 +632,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode an
* {@code int64} field, including tag.
*/
public static int computeInt64SizeNoTag(long value) {
public static int computeInt64SizeNoTag(final long value) {
return computeRawVarint64Size(value);
}
@ -652,7 +640,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode an
* {@code int32} field, including tag.
*/
public static int computeInt32SizeNoTag(int value) {
public static int computeInt32SizeNoTag(final int value) {
if (value >= 0) {
return computeRawVarint32Size(value);
} else {
@ -665,7 +653,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code fixed64} field.
*/
public static int computeFixed64SizeNoTag(long value) {
public static int computeFixed64SizeNoTag(final long value) {
return LITTLE_ENDIAN_64_SIZE;
}
@ -673,7 +661,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code fixed32} field.
*/
public static int computeFixed32SizeNoTag(int value) {
public static int computeFixed32SizeNoTag(final int value) {
return LITTLE_ENDIAN_32_SIZE;
}
@ -681,7 +669,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code bool} field.
*/
public static int computeBoolSizeNoTag(boolean value) {
public static int computeBoolSizeNoTag(final boolean value) {
return 1;
}
@ -689,12 +677,12 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code string} field.
*/
public static int computeStringSizeNoTag(String value) {
public static int computeStringSizeNoTag(final String value) {
try {
byte[] bytes = value.getBytes("UTF-8");
final byte[] bytes = value.getBytes("UTF-8");
return computeRawVarint32Size(bytes.length) +
bytes.length;
} catch (java.io.UnsupportedEncodingException e) {
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("UTF-8 not supported.", e);
}
}
@ -703,7 +691,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code group} field.
*/
public static int computeGroupSizeNoTag(Message value) {
public static int computeGroupSizeNoTag(final MessageLite value) {
return value.getSerializedSize();
}
@ -711,17 +699,21 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code group} field represented by an {@code UnknownFieldSet}, including
* tag.
*
* @deprecated UnknownFieldSet now implements MessageLite, so you can just
* call {@link #computeUnknownGroupSizeNoTag}.
*/
public static int computeUnknownGroupSizeNoTag(UnknownFieldSet value) {
return value.getSerializedSize();
@Deprecated
public static int computeUnknownGroupSizeNoTag(final MessageLite value) {
return computeGroupSizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode an embedded
* message field.
*/
public static int computeMessageSizeNoTag(Message value) {
int size = value.getSerializedSize();
public static int computeMessageSizeNoTag(final MessageLite value) {
final int size = value.getSerializedSize();
return computeRawVarint32Size(size) + size;
}
@ -729,7 +721,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code bytes} field.
*/
public static int computeBytesSizeNoTag(ByteString value) {
public static int computeBytesSizeNoTag(final ByteString value) {
return computeRawVarint32Size(value.size()) +
value.size();
}
@ -738,15 +730,15 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode a
* {@code uint32} field.
*/
public static int computeUInt32SizeNoTag(int value) {
public static int computeUInt32SizeNoTag(final int value) {
return computeRawVarint32Size(value);
}
/**
* Compute the number of bytes that would be needed to encode an enum field.
* Compute the number of bytes that would be needed to encode an enum field.
* Caller is responsible for converting the enum value to its numeric value.
*/
public static int computeEnumSizeNoTag(int value) {
public static int computeEnumSizeNoTag(final int value) {
return computeRawVarint32Size(value);
}
@ -754,7 +746,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode an
* {@code sfixed32} field.
*/
public static int computeSFixed32SizeNoTag(int value) {
public static int computeSFixed32SizeNoTag(final int value) {
return LITTLE_ENDIAN_32_SIZE;
}
@ -762,7 +754,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode an
* {@code sfixed64} field.
*/
public static int computeSFixed64SizeNoTag(long value) {
public static int computeSFixed64SizeNoTag(final long value) {
return LITTLE_ENDIAN_64_SIZE;
}
@ -770,7 +762,7 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode an
* {@code sint32} field.
*/
public static int computeSInt32SizeNoTag(int value) {
public static int computeSInt32SizeNoTag(final int value) {
return computeRawVarint32Size(encodeZigZag32(value));
}
@ -778,71 +770,10 @@ public final class CodedOutputStream {
* Compute the number of bytes that would be needed to encode an
* {@code sint64} field.
*/
public static int computeSInt64SizeNoTag(long value) {
public static int computeSInt64SizeNoTag(final long value) {
return computeRawVarint64Size(encodeZigZag64(value));
}
/**
* Compute the number of bytes that would be needed to encode a
* field of arbitrary type, including tag, to the stream.
*
* @param type The field's type.
* @param number The field's number.
* @param value Object representing the field's value. Must be of the exact
* type which would be returned by
* {@link Message#getField(Descriptors.FieldDescriptor)} for
* this field.
*/
public static int computeFieldSize(
Descriptors.FieldDescriptor.Type type,
int number, Object value) {
int tagSize = computeTagSize(number);
if (type == Descriptors.FieldDescriptor.Type.GROUP) {
tagSize *= 2;
}
return tagSize + computeFieldSizeNoTag(type, value);
}
/**
* Compute the number of bytes that would be needed to encode a
* field of arbitrary type, excluding tag, to the stream.
*
* @param type The field's type.
* @param value Object representing the field's value. Must be of the exact
* type which would be returned by
* {@link Message#getField(Descriptors.FieldDescriptor)} for
* this field.
*/
public static int computeFieldSizeNoTag(
Descriptors.FieldDescriptor.Type type, Object value) {
switch (type) {
case DOUBLE : return computeDoubleSizeNoTag ((Double )value);
case FLOAT : return computeFloatSizeNoTag ((Float )value);
case INT64 : return computeInt64SizeNoTag ((Long )value);
case UINT64 : return computeUInt64SizeNoTag ((Long )value);
case INT32 : return computeInt32SizeNoTag ((Integer )value);
case FIXED64 : return computeFixed64SizeNoTag ((Long )value);
case FIXED32 : return computeFixed32SizeNoTag ((Integer )value);
case BOOL : return computeBoolSizeNoTag ((Boolean )value);
case STRING : return computeStringSizeNoTag ((String )value);
case GROUP : return computeGroupSizeNoTag ((Message )value);
case MESSAGE : return computeMessageSizeNoTag ((Message )value);
case BYTES : return computeBytesSizeNoTag ((ByteString)value);
case UINT32 : return computeUInt32SizeNoTag ((Integer )value);
case SFIXED32: return computeSFixed32SizeNoTag((Integer )value);
case SFIXED64: return computeSFixed64SizeNoTag((Long )value);
case SINT32 : return computeSInt32SizeNoTag ((Integer )value);
case SINT64 : return computeSInt64SizeNoTag ((Long )value);
case ENUM:
return computeEnumSizeNoTag(
((Descriptors.EnumValueDescriptor)value).getNumber());
}
throw new RuntimeException(
"There is no way to get here, but the compiler thinks otherwise.");
}
// =================================================================
/**
@ -905,6 +836,8 @@ public final class CodedOutputStream {
* this exception will be thrown.
*/
public static class OutOfSpaceException extends IOException {
private static final long serialVersionUID = -6947486886997889499L;
OutOfSpaceException() {
super("CodedOutputStream was writing to a flat byte array and ran " +
"out of space.");
@ -912,7 +845,7 @@ public final class CodedOutputStream {
}
/** Write a single byte. */
public void writeRawByte(byte value) throws IOException {
public void writeRawByte(final byte value) throws IOException {
if (position == limit) {
refreshBuffer();
}
@ -921,17 +854,17 @@ public final class CodedOutputStream {
}
/** Write a single byte, represented by an integer value. */
public void writeRawByte(int value) throws IOException {
public void writeRawByte(final int value) throws IOException {
writeRawByte((byte) value);
}
/** Write an array of bytes. */
public void writeRawBytes(byte[] value) throws IOException {
public void writeRawBytes(final byte[] value) throws IOException {
writeRawBytes(value, 0, value.length);
}
/** Write part of an array of bytes. */
public void writeRawBytes(byte[] value, int offset, int length)
public void writeRawBytes(final byte[] value, int offset, int length)
throws IOException {
if (limit - position >= length) {
// We have room in the current buffer.
@ -940,7 +873,7 @@ public final class CodedOutputStream {
} else {
// Write extends past current buffer. Fill the rest of this buffer and
// flush.
int bytesWritten = limit - position;
final int bytesWritten = limit - position;
System.arraycopy(value, offset, buffer, position, bytesWritten);
offset += bytesWritten;
length -= bytesWritten;
@ -962,12 +895,13 @@ public final class CodedOutputStream {
}
/** Encode and write a tag. */
public void writeTag(int fieldNumber, int wireType) throws IOException {
public void writeTag(final int fieldNumber, final int wireType)
throws IOException {
writeRawVarint32(WireFormat.makeTag(fieldNumber, wireType));
}
/** Compute the number of bytes that would be needed to encode a tag. */
public static int computeTagSize(int fieldNumber) {
public static int computeTagSize(final int fieldNumber) {
return computeRawVarint32Size(WireFormat.makeTag(fieldNumber, 0));
}
@ -992,7 +926,7 @@ public final class CodedOutputStream {
* {@code value} is treated as unsigned, so it won't be sign-extended if
* negative.
*/
public static int computeRawVarint32Size(int value) {
public static int computeRawVarint32Size(final int value) {
if ((value & (0xffffffff << 7)) == 0) return 1;
if ((value & (0xffffffff << 14)) == 0) return 2;
if ((value & (0xffffffff << 21)) == 0) return 3;
@ -1014,7 +948,7 @@ public final class CodedOutputStream {
}
/** Compute the number of bytes that would be needed to encode a varint. */
public static int computeRawVarint64Size(long value) {
public static int computeRawVarint64Size(final long value) {
if ((value & (0xffffffffffffffffL << 7)) == 0) return 1;
if ((value & (0xffffffffffffffffL << 14)) == 0) return 2;
if ((value & (0xffffffffffffffffL << 21)) == 0) return 3;
@ -1028,7 +962,7 @@ public final class CodedOutputStream {
}
/** Write a little-endian 32-bit integer. */
public void writeRawLittleEndian32(int value) throws IOException {
public void writeRawLittleEndian32(final int value) throws IOException {
writeRawByte((value ) & 0xFF);
writeRawByte((value >> 8) & 0xFF);
writeRawByte((value >> 16) & 0xFF);
@ -1038,7 +972,7 @@ public final class CodedOutputStream {
public static final int LITTLE_ENDIAN_32_SIZE = 4;
/** Write a little-endian 64-bit integer. */
public void writeRawLittleEndian64(long value) throws IOException {
public void writeRawLittleEndian64(final long value) throws IOException {
writeRawByte((int)(value ) & 0xFF);
writeRawByte((int)(value >> 8) & 0xFF);
writeRawByte((int)(value >> 16) & 0xFF);
@ -1061,7 +995,7 @@ public final class CodedOutputStream {
* @return An unsigned 32-bit integer, stored in a signed int because
* Java has no explicit unsigned support.
*/
public static int encodeZigZag32(int n) {
public static int encodeZigZag32(final int n) {
// Note: the right-shift must be arithmetic
return (n << 1) ^ (n >> 31);
}
@ -1076,7 +1010,7 @@ public final class CodedOutputStream {
* @return An unsigned 64-bit integer, stored in a signed int because
* Java has no explicit unsigned support.
*/
public static long encodeZigZag64(long n) {
public static long encodeZigZag64(final long n) {
// Note: the right-shift must be arithmetic
return (n << 1) ^ (n >> 63);
}

File diff suppressed because it is too large Load Diff

View File

@ -45,14 +45,14 @@ import java.util.Map;
*/
public final class DynamicMessage extends AbstractMessage {
private final Descriptor type;
private final FieldSet fields;
private final FieldSet<FieldDescriptor> fields;
private final UnknownFieldSet unknownFields;
private int memoizedSize = -1;
/**
* Construct a {@code DynamicMessage} using the given {@code FieldSet}.
*/
private DynamicMessage(Descriptor type, FieldSet fields,
private DynamicMessage(Descriptor type, FieldSet<FieldDescriptor> fields,
UnknownFieldSet unknownFields) {
this.type = type;
this.fields = fields;
@ -64,7 +64,7 @@ public final class DynamicMessage extends AbstractMessage {
* given type.
*/
public static DynamicMessage getDefaultInstance(Descriptor type) {
return new DynamicMessage(type, FieldSet.emptySet(),
return new DynamicMessage(type, FieldSet.<FieldDescriptor>emptySet(),
UnknownFieldSet.getDefaultInstance());
}
@ -160,7 +160,11 @@ public final class DynamicMessage extends AbstractMessage {
verifyContainingType(field);
Object result = fields.getField(field);
if (result == null) {
result = getDefaultInstance(field.getMessageType());
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
result = getDefaultInstance(field.getMessageType());
} else {
result = field.getDefaultValue();
}
}
return result;
}
@ -179,15 +183,31 @@ public final class DynamicMessage extends AbstractMessage {
return unknownFields;
}
private static boolean isInitialized(Descriptor type,
FieldSet<FieldDescriptor> fields) {
// Check that all required fields are present.
for (final FieldDescriptor field : type.getFields()) {
if (field.isRequired()) {
if (!fields.hasField(field)) {
return false;
}
}
}
// Check that embedded messages are initialized.
return fields.isInitialized();
}
public boolean isInitialized() {
return fields.isInitialized(type);
return isInitialized(type, fields);
}
public void writeTo(CodedOutputStream output) throws IOException {
fields.writeTo(output);
if (type.getOptions().getMessageSetWireFormat()) {
fields.writeMessageSetTo(output);
unknownFields.writeAsMessageSetTo(output);
} else {
fields.writeTo(output);
unknownFields.writeTo(output);
}
}
@ -196,10 +216,11 @@ public final class DynamicMessage extends AbstractMessage {
int size = memoizedSize;
if (size != -1) return size;
size = fields.getSerializedSize();
if (type.getOptions().getMessageSetWireFormat()) {
size = fields.getMessageSetSerializedSize();
size += unknownFields.getSerializedSizeAsMessageSet();
} else {
size = fields.getSerializedSize();
size += unknownFields.getSerializedSize();
}
@ -230,7 +251,7 @@ public final class DynamicMessage extends AbstractMessage {
*/
public static final class Builder extends AbstractMessage.Builder<Builder> {
private final Descriptor type;
private FieldSet fields;
private FieldSet<FieldDescriptor> fields;
private UnknownFieldSet unknownFields;
/** Construct a {@code Builder} for the given type. */
@ -244,25 +265,33 @@ public final class DynamicMessage extends AbstractMessage {
// Implementation of Message.Builder interface.
public Builder clear() {
if (fields == null) {
throw new IllegalStateException("Cannot call clear() after build().");
}
fields.clear();
return this;
}
public Builder mergeFrom(Message other) {
if (other.getDescriptorForType() != type) {
throw new IllegalArgumentException(
"mergeFrom(Message) can only merge messages of the same type.");
if (other instanceof DynamicMessage) {
// This should be somewhat faster than calling super.mergeFrom().
DynamicMessage otherDynamicMessage = (DynamicMessage) other;
if (otherDynamicMessage.type != type) {
throw new IllegalArgumentException(
"mergeFrom(Message) can only merge messages of the same type.");
}
fields.mergeFrom(otherDynamicMessage.fields);
mergeUnknownFields(otherDynamicMessage.unknownFields);
return this;
} else {
return super.mergeFrom(other);
}
fields.mergeFrom(other);
mergeUnknownFields(other.getUnknownFields());
return this;
}
public DynamicMessage build() {
// If fields == null, we'll throw an appropriate exception later.
if (fields != null && !isInitialized()) {
throw new UninitializedMessageException(
throw newUninitializedMessageException(
new DynamicMessage(type, fields, unknownFields));
}
return buildPartial();
@ -275,7 +304,7 @@ public final class DynamicMessage extends AbstractMessage {
*/
private DynamicMessage buildParsed() throws InvalidProtocolBufferException {
if (!isInitialized()) {
throw new UninitializedMessageException(
throw newUninitializedMessageException(
new DynamicMessage(type, fields, unknownFields))
.asInvalidProtocolBufferException();
}
@ -302,17 +331,7 @@ public final class DynamicMessage extends AbstractMessage {
}
public boolean isInitialized() {
return fields.isInitialized(type);
}
public Builder mergeFrom(CodedInputStream input,
ExtensionRegistry extensionRegistry)
throws IOException {
UnknownFieldSet.Builder unknownFieldsBuilder =
UnknownFieldSet.newBuilder(unknownFields);
fields.mergeFrom(input, unknownFieldsBuilder, extensionRegistry, this);
unknownFields = unknownFieldsBuilder.build();
return this;
return DynamicMessage.isInitialized(type, fields);
}
public Descriptor getDescriptorForType() {
@ -347,7 +366,11 @@ public final class DynamicMessage extends AbstractMessage {
verifyContainingType(field);
Object result = fields.getField(field);
if (result == null) {
result = getDefaultInstance(field.getMessageType());
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
result = getDefaultInstance(field.getMessageType());
} else {
result = field.getDefaultValue();
}
}
return result;
}

View File

@ -84,18 +84,16 @@ import java.util.Map;
* would be slow. Second, corrupt data would not be detected until first
* access, at which point it would be much harder to deal with it. Third, it
* could violate the expectation that message objects are immutable, since the
* type provided could be any arbitrary message class. An unpriviledged user
* type provided could be any arbitrary message class. An unprivileged user
* could take advantage of this to inject a mutable object into a message
* belonging to priviledged code and create mischief.
* belonging to privileged code and create mischief.
*
* @author kenton@google.com Kenton Varda
*/
public final class ExtensionRegistry {
public final class ExtensionRegistry extends ExtensionRegistryLite {
/** Construct a new, empty instance. */
public static ExtensionRegistry newInstance() {
return new ExtensionRegistry(
new HashMap<String, ExtensionInfo>(),
new HashMap<DescriptorIntPair, ExtensionInfo>());
return new ExtensionRegistry();
}
/** Get the unmodifiable singleton empty instance. */
@ -104,10 +102,9 @@ public final class ExtensionRegistry {
}
/** Returns an unmodifiable view of the registry. */
@Override
public ExtensionRegistry getUnmodifiable() {
return new ExtensionRegistry(
Collections.unmodifiableMap(extensionsByName),
Collections.unmodifiableMap(extensionsByNumber));
return new ExtensionRegistry(this);
}
/** A (Descriptor, Message) pair, returned by lookup methods. */
@ -121,11 +118,12 @@ public final class ExtensionRegistry {
*/
public final Message defaultInstance;
private ExtensionInfo(FieldDescriptor descriptor) {
private ExtensionInfo(final FieldDescriptor descriptor) {
this.descriptor = descriptor;
this.defaultInstance = null;
defaultInstance = null;
}
private ExtensionInfo(FieldDescriptor descriptor, Message defaultInstance) {
private ExtensionInfo(final FieldDescriptor descriptor,
final Message defaultInstance) {
this.descriptor = descriptor;
this.defaultInstance = defaultInstance;
}
@ -139,7 +137,7 @@ public final class ExtensionRegistry {
* @return Information about the extension if found, or {@code null}
* otherwise.
*/
public ExtensionInfo findExtensionByName(String fullName) {
public ExtensionInfo findExtensionByName(final String fullName) {
return extensionsByName.get(fullName);
}
@ -149,14 +147,14 @@ public final class ExtensionRegistry {
* @return Information about the extension if found, or {@code null}
* otherwise.
*/
public ExtensionInfo findExtensionByNumber(Descriptor containingType,
int fieldNumber) {
public ExtensionInfo findExtensionByNumber(final Descriptor containingType,
final int fieldNumber) {
return extensionsByNumber.get(
new DescriptorIntPair(containingType, fieldNumber));
}
/** Add an extension from a generated file to the registry. */
public void add(GeneratedMessage.GeneratedExtension<?, ?> extension) {
public void add(final GeneratedMessage.GeneratedExtension<?, ?> extension) {
if (extension.getDescriptor().getJavaType() ==
FieldDescriptor.JavaType.MESSAGE) {
add(new ExtensionInfo(extension.getDescriptor(),
@ -167,7 +165,7 @@ public final class ExtensionRegistry {
}
/** Add a non-message-type extension to the registry by descriptor. */
public void add(FieldDescriptor type) {
public void add(final FieldDescriptor type) {
if (type.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
throw new IllegalArgumentException(
"ExtensionRegistry.add() must be provided a default instance when " +
@ -177,7 +175,7 @@ public final class ExtensionRegistry {
}
/** Add a message-type extension to the registry by descriptor. */
public void add(FieldDescriptor type, Message defaultInstance) {
public void add(final FieldDescriptor type, final Message defaultInstance) {
if (type.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
throw new IllegalArgumentException(
"ExtensionRegistry.add() provided a default instance for a " +
@ -189,22 +187,30 @@ public final class ExtensionRegistry {
// =================================================================
// Private stuff.
private ExtensionRegistry(
Map<String, ExtensionInfo> extensionsByName,
Map<DescriptorIntPair, ExtensionInfo> extensionsByNumber) {
this.extensionsByName = extensionsByName;
this.extensionsByNumber = extensionsByNumber;
private ExtensionRegistry() {
this.extensionsByName = new HashMap<String, ExtensionInfo>();
this.extensionsByNumber = new HashMap<DescriptorIntPair, ExtensionInfo>();
}
private ExtensionRegistry(ExtensionRegistry other) {
super(other);
this.extensionsByName = Collections.unmodifiableMap(other.extensionsByName);
this.extensionsByNumber =
Collections.unmodifiableMap(other.extensionsByNumber);
}
private final Map<String, ExtensionInfo> extensionsByName;
private final Map<DescriptorIntPair, ExtensionInfo> extensionsByNumber;
private static final ExtensionRegistry EMPTY =
new ExtensionRegistry(
Collections.<String, ExtensionInfo>emptyMap(),
Collections.<DescriptorIntPair, ExtensionInfo>emptyMap());
private ExtensionRegistry(boolean empty) {
super(ExtensionRegistryLite.getEmptyRegistry());
this.extensionsByName = Collections.<String, ExtensionInfo>emptyMap();
this.extensionsByNumber =
Collections.<DescriptorIntPair, ExtensionInfo>emptyMap();
}
private static final ExtensionRegistry EMPTY = new ExtensionRegistry(true);
private void add(ExtensionInfo extension) {
private void add(final ExtensionInfo extension) {
if (!extension.descriptor.isExtension()) {
throw new IllegalArgumentException(
"ExtensionRegistry.add() was given a FieldDescriptor for a regular " +
@ -217,7 +223,7 @@ public final class ExtensionRegistry {
extension.descriptor.getNumber()),
extension);
FieldDescriptor field = extension.descriptor;
final FieldDescriptor field = extension.descriptor;
if (field.getContainingType().getOptions().getMessageSetWireFormat() &&
field.getType() == FieldDescriptor.Type.MESSAGE &&
field.isOptional() &&
@ -231,20 +237,24 @@ public final class ExtensionRegistry {
/** A (GenericDescriptor, int) pair, used as a map key. */
private static final class DescriptorIntPair {
final Descriptor descriptor;
final int number;
private final Descriptor descriptor;
private final int number;
DescriptorIntPair(Descriptor descriptor, int number) {
DescriptorIntPair(final Descriptor descriptor, final int number) {
this.descriptor = descriptor;
this.number = number;
}
@Override
public int hashCode() {
return descriptor.hashCode() * ((1 << 16) - 1) + number;
}
public boolean equals(Object obj) {
if (!(obj instanceof DescriptorIntPair)) return false;
DescriptorIntPair other = (DescriptorIntPair)obj;
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof DescriptorIntPair)) {
return false;
}
final DescriptorIntPair other = (DescriptorIntPair)obj;
return descriptor == other.descriptor && number == other.number;
}
}

View File

@ -0,0 +1,169 @@
// 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.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Equivalent to {@link ExtensionRegistry} but supports only "lite" types.
* <p>
* If all of your types are lite types, then you only need to use
* {@code ExtensionRegistryLite}. Similarly, if all your types are regular
* types, then you only need {@link ExtensionRegistry}. Typically it does not
* make sense to mix the two, since if you have any regular types in your
* program, you then require the full runtime and lose all the benefits of
* the lite runtime, so you might as well make all your types be regular types.
* However, in some cases (e.g. when depending on multiple third-patry libraries
* where one uses lite types and one uses regular), you may find yourself
* wanting to mix the two. In this case things get more complicated.
* <p>
* There are three factors to consider: Whether the type being extended is
* lite, whether the embedded type (in the case of a message-typed extension)
* is lite, and whether the extension itself is lite. Since all three are
* declared in different files, they could all be different. Here are all
* the combinations and which type of registry to use:
* <pre>
* Extended type Inner type Extension Use registry
* =======================================================================
* lite lite lite ExtensionRegistryLite
* lite regular lite ExtensionRegistry
* regular regular regular ExtensionRegistry
* all other combinations not supported
* </pre>
* <p>
* Note that just as regular types are not allowed to contain lite-type fields,
* they are also not allowed to contain lite-type extensions. This is because
* regular types must be fully accessible via reflection, which in turn means
* that all the inner messages must also support reflection. On the other hand,
* since regular types implement the entire lite interface, there is no problem
* with embedding regular types inside lite types.
*
* @author kenton@google.com Kenton Varda
*/
public class ExtensionRegistryLite {
/** Construct a new, empty instance. */
public static ExtensionRegistryLite newInstance() {
return new ExtensionRegistryLite();
}
/** Get the unmodifiable singleton empty instance. */
public static ExtensionRegistryLite getEmptyRegistry() {
return EMPTY;
}
/** Returns an unmodifiable view of the registry. */
public ExtensionRegistryLite getUnmodifiable() {
return new ExtensionRegistryLite(this);
}
/**
* Find an extension by containing type and field number.
*
* @return Information about the extension if found, or {@code null}
* otherwise.
*/
@SuppressWarnings("unchecked")
public <ContainingType extends MessageLite>
GeneratedMessageLite.GeneratedExtension<ContainingType, ?>
findLiteExtensionByNumber(
final ContainingType containingTypeDefaultInstance,
final int fieldNumber) {
return (GeneratedMessageLite.GeneratedExtension<ContainingType, ?>)
extensionsByNumber.get(
new ObjectIntPair(containingTypeDefaultInstance, fieldNumber));
}
/** Add an extension from a lite generated file to the registry. */
public final void add(
final GeneratedMessageLite.GeneratedExtension<?, ?> extension) {
extensionsByNumber.put(
new ObjectIntPair(extension.getContainingTypeDefaultInstance(),
extension.getNumber()),
extension);
}
// =================================================================
// Private stuff.
// Constructors are package-private so that ExtensionRegistry can subclass
// this.
ExtensionRegistryLite() {
this.extensionsByNumber =
new HashMap<ObjectIntPair,
GeneratedMessageLite.GeneratedExtension<?, ?>>();
}
ExtensionRegistryLite(ExtensionRegistryLite other) {
if (other == EMPTY) {
this.extensionsByNumber = Collections.emptyMap();
} else {
this.extensionsByNumber =
Collections.unmodifiableMap(other.extensionsByNumber);
}
}
private final Map<ObjectIntPair,
GeneratedMessageLite.GeneratedExtension<?, ?>>
extensionsByNumber;
private ExtensionRegistryLite(boolean empty) {
this.extensionsByNumber = Collections.emptyMap();
}
private static final ExtensionRegistryLite EMPTY =
new ExtensionRegistryLite(true);
/** A (Object, int) pair, used as a map key. */
private static final class ObjectIntPair {
private final Object object;
private final int number;
ObjectIntPair(final Object object, final int number) {
this.object = object;
this.number = number;
}
@Override
public int hashCode() {
return System.identityHashCode(object) * ((1 << 16) - 1) + number;
}
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof ObjectIntPair)) {
return false;
}
final ObjectIntPair other = (ObjectIntPair)obj;
return object == other.object && number == other.number;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,539 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Lite version of {@link GeneratedMessage}.
*
* @author kenton@google.com Kenton Varda
*/
public abstract class GeneratedMessageLite extends AbstractMessageLite {
protected GeneratedMessageLite() {}
@SuppressWarnings("unchecked")
public abstract static class Builder<MessageType extends GeneratedMessageLite,
BuilderType extends Builder>
extends AbstractMessageLite.Builder<BuilderType> {
protected Builder() {}
// This is implemented here only to work around an apparent bug in the
// Java compiler and/or build system. See bug #1898463. The mere presence
// of this dummy clone() implementation makes it go away.
@Override
public BuilderType clone() {
throw new UnsupportedOperationException(
"This is supposed to be overridden by subclasses.");
}
/** All subclasses implement this. */
public abstract BuilderType mergeFrom(MessageType message);
// Defined here for return type covariance.
public abstract MessageType getDefaultInstanceForType();
/**
* Get the message being built. We don't just pass this to the
* constructor because it becomes null when build() is called.
*/
protected abstract MessageType internalGetResult();
/**
* Called by subclasses to parse an unknown field.
* @return {@code true} unless the tag is an end-group tag.
*/
protected boolean parseUnknownField(
final CodedInputStream input,
final ExtensionRegistryLite extensionRegistry,
final int tag) throws IOException {
return input.skipField(tag);
}
}
// =================================================================
// Extensions-related stuff
/**
* Lite equivalent of {@link GeneratedMessage.ExtendableMessage}.
*/
public abstract static class ExtendableMessage<
MessageType extends ExtendableMessage<MessageType>>
extends GeneratedMessageLite {
protected ExtendableMessage() {}
private final FieldSet<ExtensionDescriptor> extensions =
FieldSet.newFieldSet();
private void verifyExtensionContainingType(
final GeneratedExtension<MessageType, ?> extension) {
if (extension.getContainingTypeDefaultInstance() !=
getDefaultInstanceForType()) {
// This can only happen if someone uses unchecked operations.
throw new IllegalArgumentException(
"This extension is for a different message type. Please make " +
"sure that you are not suppressing any generics type warnings.");
}
}
/** Check if a singular extension is present. */
public final boolean hasExtension(
final GeneratedExtension<MessageType, ?> extension) {
verifyExtensionContainingType(extension);
return extensions.hasField(extension.descriptor);
}
/** Get the number of elements in a repeated extension. */
public final <Type> int getExtensionCount(
final GeneratedExtension<MessageType, List<Type>> extension) {
verifyExtensionContainingType(extension);
return extensions.getRepeatedFieldCount(extension.descriptor);
}
/** Get the value of an extension. */
@SuppressWarnings("unchecked")
public final <Type> Type getExtension(
final GeneratedExtension<MessageType, Type> extension) {
verifyExtensionContainingType(extension);
final Object value = extensions.getField(extension.descriptor);
if (value == null) {
return extension.defaultValue;
} else {
return (Type) value;
}
}
/** Get one element of a repeated extension. */
@SuppressWarnings("unchecked")
public final <Type> Type getExtension(
final GeneratedExtension<MessageType, List<Type>> extension,
final int index) {
verifyExtensionContainingType(extension);
return (Type) extensions.getRepeatedField(extension.descriptor, index);
}
/** Called by subclasses to check if all extensions are initialized. */
protected boolean extensionsAreInitialized() {
return extensions.isInitialized();
}
/**
* Used by subclasses to serialize extensions. Extension ranges may be
* interleaved with field numbers, but we must write them in canonical
* (sorted by field number) order. ExtensionWriter helps us write
* individual ranges of extensions at once.
*/
protected class ExtensionWriter {
// Imagine how much simpler this code would be if Java iterators had
// a way to get the next element without advancing the iterator.
private final Iterator<Map.Entry<ExtensionDescriptor, Object>> iter =
extensions.iterator();
private Map.Entry<ExtensionDescriptor, Object> next;
private final boolean messageSetWireFormat;
private ExtensionWriter(boolean messageSetWireFormat) {
if (iter.hasNext()) {
next = iter.next();
}
this.messageSetWireFormat = messageSetWireFormat;
}
public void writeUntil(final int end, final CodedOutputStream output)
throws IOException {
while (next != null && next.getKey().getNumber() < end) {
ExtensionDescriptor extension = next.getKey();
if (messageSetWireFormat && extension.getLiteJavaType() ==
WireFormat.JavaType.MESSAGE &&
!extension.isRepeated()) {
output.writeMessageSetExtension(extension.getNumber(),
(MessageLite) next.getValue());
} else {
FieldSet.writeField(extension, next.getValue(), output);
}
if (iter.hasNext()) {
next = iter.next();
} else {
next = null;
}
}
}
}
protected ExtensionWriter newExtensionWriter() {
return new ExtensionWriter(false);
}
protected ExtensionWriter newMessageSetExtensionWriter() {
return new ExtensionWriter(true);
}
/** Called by subclasses to compute the size of extensions. */
protected int extensionsSerializedSize() {
return extensions.getSerializedSize();
}
protected int extensionsSerializedSizeAsMessageSet() {
return extensions.getMessageSetSerializedSize();
}
}
/**
* Lite equivalent of {@link GeneratedMessage.ExtendableBuilder}.
*/
@SuppressWarnings("unchecked")
public abstract static class ExtendableBuilder<
MessageType extends ExtendableMessage<MessageType>,
BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
extends Builder<MessageType, BuilderType> {
protected ExtendableBuilder() {}
// This is implemented here only to work around an apparent bug in the
// Java compiler and/or build system. See bug #1898463. The mere presence
// of this dummy clone() implementation makes it go away.
@Override
public BuilderType clone() {
throw new UnsupportedOperationException(
"This is supposed to be overridden by subclasses.");
}
@Override
protected abstract MessageType internalGetResult();
/** Check if a singular extension is present. */
public final boolean hasExtension(
final GeneratedExtension<MessageType, ?> extension) {
return internalGetResult().hasExtension(extension);
}
/** Get the number of elements in a repeated extension. */
public final <Type> int getExtensionCount(
final GeneratedExtension<MessageType, List<Type>> extension) {
return internalGetResult().getExtensionCount(extension);
}
/** Get the value of an extension. */
public final <Type> Type getExtension(
final GeneratedExtension<MessageType, Type> extension) {
return internalGetResult().getExtension(extension);
}
/** Get one element of a repeated extension. */
public final <Type> Type getExtension(
final GeneratedExtension<MessageType, List<Type>> extension,
final int index) {
return internalGetResult().getExtension(extension, index);
}
/** Set the value of an extension. */
public final <Type> BuilderType setExtension(
final GeneratedExtension<MessageType, Type> extension,
final Type value) {
final ExtendableMessage<MessageType> message = internalGetResult();
message.verifyExtensionContainingType(extension);
message.extensions.setField(extension.descriptor, value);
return (BuilderType) this;
}
/** Set the value of one element of a repeated extension. */
public final <Type> BuilderType setExtension(
final GeneratedExtension<MessageType, List<Type>> extension,
final int index, final Type value) {
final ExtendableMessage<MessageType> message = internalGetResult();
message.verifyExtensionContainingType(extension);
message.extensions.setRepeatedField(extension.descriptor, index, value);
return (BuilderType) this;
}
/** Append a value to a repeated extension. */
public final <Type> BuilderType addExtension(
final GeneratedExtension<MessageType, List<Type>> extension,
final Type value) {
final ExtendableMessage<MessageType> message = internalGetResult();
message.verifyExtensionContainingType(extension);
message.extensions.addRepeatedField(extension.descriptor, value);
return (BuilderType) this;
}
/** Clear an extension. */
public final <Type> BuilderType clearExtension(
final GeneratedExtension<MessageType, ?> extension) {
final ExtendableMessage<MessageType> message = internalGetResult();
message.verifyExtensionContainingType(extension);
message.extensions.clearField(extension.descriptor);
return (BuilderType) this;
}
/**
* Called by subclasses to parse an unknown field or an extension.
* @return {@code true} unless the tag is an end-group tag.
*/
@Override
protected boolean parseUnknownField(
final CodedInputStream input,
final ExtensionRegistryLite extensionRegistry,
final int tag) throws IOException {
final FieldSet<ExtensionDescriptor> extensions =
internalGetResult().extensions;
final int wireType = WireFormat.getTagWireType(tag);
final int fieldNumber = WireFormat.getTagFieldNumber(tag);
final GeneratedExtension<MessageType, ?> extension =
extensionRegistry.findLiteExtensionByNumber(
getDefaultInstanceForType(), fieldNumber);
if (extension == null || wireType !=
FieldSet.getWireFormatForFieldType(
extension.descriptor.getLiteType(),
extension.descriptor.isPacked())) {
// Unknown field or wrong wire type. Skip.
return input.skipField(tag);
}
if (extension.descriptor.isPacked()) {
final int length = input.readRawVarint32();
final int limit = input.pushLimit(length);
if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
while (input.getBytesUntilLimit() > 0) {
final int rawValue = input.readEnum();
final Object value =
extension.descriptor.getEnumType().findValueByNumber(rawValue);
if (value == null) {
// If the number isn't recognized as a valid value for this
// enum, drop it (don't even add it to unknownFields).
return true;
}
extensions.addRepeatedField(extension.descriptor, value);
}
} else {
while (input.getBytesUntilLimit() > 0) {
final Object value =
FieldSet.readPrimitiveField(input,
extension.descriptor.getLiteType());
extensions.addRepeatedField(extension.descriptor, value);
}
}
input.popLimit(limit);
} else {
final Object value;
switch (extension.descriptor.getLiteJavaType()) {
case MESSAGE: {
MessageLite.Builder subBuilder = null;
if (!extension.descriptor.isRepeated()) {
MessageLite existingValue =
(MessageLite) extensions.getField(extension.descriptor);
if (existingValue != null) {
subBuilder = existingValue.toBuilder();
}
}
if (subBuilder == null) {
subBuilder = extension.messageDefaultInstance.newBuilderForType();
}
if (extension.descriptor.getLiteType() ==
WireFormat.FieldType.GROUP) {
input.readGroup(extension.getNumber(),
subBuilder, extensionRegistry);
} else {
input.readMessage(subBuilder, extensionRegistry);
}
value = subBuilder.build();
break;
}
case ENUM:
final int rawValue = input.readEnum();
value = extension.descriptor.getEnumType()
.findValueByNumber(rawValue);
// If the number isn't recognized as a valid value for this enum,
// drop it.
if (value == null) {
return true;
}
break;
default:
value = FieldSet.readPrimitiveField(input,
extension.descriptor.getLiteType());
break;
}
if (extension.descriptor.isRepeated()) {
extensions.addRepeatedField(extension.descriptor, value);
} else {
extensions.setField(extension.descriptor, value);
}
}
return true;
}
protected final void mergeExtensionFields(final MessageType other) {
internalGetResult().extensions.mergeFrom(other.extensions);
}
}
// -----------------------------------------------------------------
/** For use by generated code only. */
public static <ContainingType extends MessageLite, Type>
GeneratedExtension<ContainingType, Type>
newGeneratedExtension(
final ContainingType containingTypeDefaultInstance,
final Type defaultValue,
final MessageLite messageDefaultInstance,
final Internal.EnumLiteMap<?> enumTypeMap,
final int number,
final WireFormat.FieldType type) {
return new GeneratedExtension<ContainingType, Type>(
containingTypeDefaultInstance, defaultValue, messageDefaultInstance,
new ExtensionDescriptor(enumTypeMap, number, type,
false /* isRepeated */, false /* isPacked */));
}
/** For use by generated code only. */
public static <ContainingType extends MessageLite, Type>
GeneratedExtension<ContainingType, List<Type>>
newRepeatedGeneratedExtension(
final ContainingType containingTypeDefaultInstance,
final MessageLite messageDefaultInstance,
final Internal.EnumLiteMap<?> enumTypeMap,
final int number,
final WireFormat.FieldType type,
final boolean isPacked) {
return new GeneratedExtension<ContainingType, List<Type>>(
containingTypeDefaultInstance, Collections.<Type>emptyList(),
messageDefaultInstance,
new ExtensionDescriptor(
enumTypeMap, number, type, true /* isRepeated */, isPacked));
}
private static final class ExtensionDescriptor
implements FieldSet.FieldDescriptorLite<
ExtensionDescriptor> {
private ExtensionDescriptor(
final Internal.EnumLiteMap<?> enumTypeMap,
final int number,
final WireFormat.FieldType type,
final boolean isRepeated,
final boolean isPacked) {
this.enumTypeMap = enumTypeMap;
this.number = number;
this.type = type;
this.isRepeated = isRepeated;
this.isPacked = isPacked;
}
private final Internal.EnumLiteMap<?> enumTypeMap;
private final int number;
private final WireFormat.FieldType type;
private final boolean isRepeated;
private final boolean isPacked;
public int getNumber() {
return number;
}
public WireFormat.FieldType getLiteType() {
return type;
}
public WireFormat.JavaType getLiteJavaType() {
return type.getJavaType();
}
public boolean isRepeated() {
return isRepeated;
}
public boolean isPacked() {
return isPacked;
}
public Internal.EnumLiteMap<?> getEnumType() {
return enumTypeMap;
}
@SuppressWarnings("unchecked")
public MessageLite.Builder internalMergeFrom(
MessageLite.Builder to, MessageLite from) {
return ((Builder) to).mergeFrom((GeneratedMessageLite) from);
}
public int compareTo(ExtensionDescriptor other) {
return number - other.number;
}
}
/**
* Lite equivalent to {@link GeneratedMessage.GeneratedExtension}.
*
* Users should ignore the contents of this class and only use objects of
* this type as parameters to extension accessors and ExtensionRegistry.add().
*/
public static final class GeneratedExtension<
ContainingType extends MessageLite, Type> {
private GeneratedExtension(
final ContainingType containingTypeDefaultInstance,
final Type defaultValue,
final MessageLite messageDefaultInstance,
final ExtensionDescriptor descriptor) {
this.containingTypeDefaultInstance = containingTypeDefaultInstance;
this.defaultValue = defaultValue;
this.messageDefaultInstance = messageDefaultInstance;
this.descriptor = descriptor;
}
private final ContainingType containingTypeDefaultInstance;
private final Type defaultValue;
private final MessageLite messageDefaultInstance;
private final ExtensionDescriptor descriptor;
/**
* Default instance of the type being extended, used to identify that type.
*/
public ContainingType getContainingTypeDefaultInstance() {
return containingTypeDefaultInstance;
}
/** Get the field number. */
public int getNumber() {
return descriptor.getNumber();
}
/**
* If the extension is an embedded message, this is the default instance of
* that type.
*/
public MessageLite getMessageDefaultInstance() {
return messageDefaultInstance;
}
}
}

View File

@ -0,0 +1,194 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.UnsupportedEncodingException;
/**
* The classes contained within are used internally by the Protocol Buffer
* library and generated message implementations. They are public only because
* those generated messages do not reside in the {@code protobuf} package.
* Others should not use this class directly.
*
* @author cyrusn@google.com (Cyrus Najmabadi)
*/
public class Internal {
/**
* Implementation of a Queue designed to have as little overhead as possible.
* No guarantees are made as to the order you will get values back from the
* queue. Currently it is a Last-In-First-Out implementation, but that may
* change in the future.
*
* Duplicate values are allowed, as are null values.
*
* Not threadsafe.
*
* @author cyrusn@google.com (Cyrus Najmabadi)
*/
public static final class QuickQueue<T> {
@SuppressWarnings("unchecked")
private T[] array = (T[]) new Object[16];
private int size;
/**
* Adds a value to the queue.
*
* @param value The value to add to the queue.
*/
public void offer(final T value) {
if (size == array.length) {
// I'd like to use Arrays.copy here. However, it is currently
// unavailable
// on android. So, for now, we just use the tried and true arraycopy
// technique.
@SuppressWarnings("unchecked")
final T[] copy = (T[]) new Object[size * 2];
System.arraycopy(array, 0, copy, 0, array.length);
array = copy;
}
array[size++] = value;
}
/**
* Removes some previously added value to the queue, or {@code null} if the
* queue is empty.
*
* @return An existing value in the queue, or {@code null} if the queue is
* empty.
*/
public T poll() {
if (size == 0) {
return null;
}
final T result = array[--size];
// make sure we null out the entry so that we're not keeping anything
// alive unnecessarily.
array[size] = null;
return result;
}
}
/**
* Instances of this class will provide a unique {@code QuickQueue} to each
* thread that accesses it. Very useful for providing free lists without
* needing to take any locks.
*
* @author cyrusn@google.com (Cyrus Najmabadi)
*/
public static final class ThreadLocalQuickQueue<T>
extends ThreadLocal<QuickQueue<T>> {
@Override
protected QuickQueue<T> initialValue() {
return new QuickQueue<T>();
}
}
/**
* Helper called by generated code to construct default values for string
* fields.
* <p>
* The protocol compiler does not actually contain a UTF-8 decoder -- it
* just pushes UTF-8-encoded text around without touching it. The one place
* where this presents a problem is when generating Java string literals.
* Unicode characters in the string literal would normally need to be encoded
* using a Unicode escape sequence, which would require decoding them.
* To get around this, protoc instead embeds the UTF-8 bytes into the
* generated code and leaves it to the runtime library to decode them.
* <p>
* It gets worse, though. If protoc just generated a byte array, like:
* new byte[] {0x12, 0x34, 0x56, 0x78}
* Java actually generates *code* which allocates an array and then fills
* in each value. This is much less efficient than just embedding the bytes
* directly into the bytecode. To get around this, we need another
* work-around. String literals are embedded directly, so protoc actually
* generates a string literal corresponding to the bytes. The easiest way
* to do this is to use the ISO-8859-1 character set, which corresponds to
* the first 256 characters of the Unicode range. Protoc can then use
* good old CEscape to generate the string.
* <p>
* So we have a string literal which represents a set of bytes which
* represents another string. This function -- stringDefaultValue --
* converts from the generated string to the string we actually want. The
* generated code calls this automatically.
*/
public static String stringDefaultValue(String bytes) {
try {
return new String(bytes.getBytes("ISO-8859-1"), "UTF-8");
} catch (UnsupportedEncodingException e) {
// This should never happen since all JVMs are required to implement
// both of the above character sets.
throw new IllegalStateException(
"Java VM does not support a standard character set.", e);
}
}
/**
* Helper called by generated code to construct default values for bytes
* fields.
* <p>
* This is a lot like {@link #stringDefaultValue}, but for bytes fields.
* In this case we only need the second of the two hacks -- allowing us to
* embed raw bytes as a string literal with ISO-8859-1 encoding.
*/
public static ByteString bytesDefaultValue(String bytes) {
try {
return ByteString.copyFrom(bytes.getBytes("ISO-8859-1"));
} catch (UnsupportedEncodingException e) {
// This should never happen since all JVMs are required to implement
// ISO-8859-1.
throw new IllegalStateException(
"Java VM does not support a standard character set.", e);
}
}
/**
* Interface for an enum value or value descriptor, to be used in FieldSet.
* The lite library stores enum values directly in FieldSets but the full
* library stores EnumValueDescriptors in order to better support reflection.
*/
public interface EnumLite {
int getNumber();
}
/**
* Interface for an object which maps integers to {@link EnumLite}s.
* {@link Descriptors.EnumDescriptor} implements this interface by mapping
* numbers to {@link Descriptors.EnumValueDescriptor}s. Additionally,
* every generated enum type has a static method internalGetValueMap() which
* returns an implementation of this type that maps numbers to enum values.
*/
public interface EnumLiteMap<T extends EnumLite> {
T findValueByNumber(int number);
}
}

View File

@ -39,7 +39,9 @@ import java.io.IOException;
* @author kenton@google.com Kenton Varda
*/
public class InvalidProtocolBufferException extends IOException {
public InvalidProtocolBufferException(String description) {
private static final long serialVersionUID = -1616151763072450476L;
public InvalidProtocolBufferException(final String description) {
super(description);
}

View File

@ -33,17 +33,22 @@
package com.google.protobuf;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.InputStream;
import java.util.Map;
/**
* Abstract interface implemented by Protocol Message objects.
* <p>
* See also {@link MessageLite}, which defines most of the methods that typical
* users care about. {@link Message} adds to it methods that are not available
* in the "lite" runtime. The biggest added features are introspection and
* reflection -- i.e., getting descriptors for the message type and accessing
* the field values dynamically.
*
* @author kenton@google.com Kenton Varda
*/
public interface Message {
public interface Message extends MessageLite {
/**
* Get the message's type's descriptor. This differs from the
* {@code getDescriptor()} method of generated message classes in that
@ -53,14 +58,7 @@ public interface Message {
*/
Descriptors.Descriptor getDescriptorForType();
/**
* 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 Message} interface
* whereas {@code getDefaultInstance()} is a static method of a specific
* class. They return the same thing.
*/
// (From MessageLite, re-declared here only for return type covariance.)
Message getDefaultInstanceForType();
/**
@ -114,24 +112,6 @@ public interface Message {
/** Get the {@link UnknownFieldSet} for this message. */
UnknownFieldSet getUnknownFields();
/**
* Returns true if all required fields in the message and all embedded
* messages are set, false otherwise.
*/
boolean isInitialized();
/**
* Serializes the message and writes it to {@code output}. This does not
* flush or close the stream.
*/
void writeTo(CodedOutputStream output) throws IOException;
/**
* Get the number of bytes required to encode this message. The result
* is only computed on the first call and memoized after that.
*/
int getSerializedSize();
// -----------------------------------------------------------------
// Comparison and hashing
@ -144,6 +124,7 @@ public interface Message {
* @param other object to be compared for equality with this message
* @return <tt>true</tt> if the specified object is equal to this message
*/
@Override
boolean equals(Object other);
/**
@ -154,6 +135,7 @@ public interface Message {
* @return the hash code value for this message
* @see Map#hashCode()
*/
@Override
int hashCode();
// -----------------------------------------------------------------
@ -163,67 +145,22 @@ public interface Message {
* Converts the message to a string in protocol buffer text format. This is
* just a trivial wrapper around {@link TextFormat#printToString(Message)}.
*/
@Override
String toString();
/**
* Serializes the message to a {@code ByteString} and returns it. This is
* just a trivial wrapper around
* {@link #writeTo(CodedOutputStream)}.
*/
ByteString toByteString();
/**
* Serializes the message to a {@code byte} array and returns it. This is
* just a trivial wrapper around
* {@link #writeTo(CodedOutputStream)}.
*/
byte[] toByteArray();
/**
* Serializes the message and writes it to {@code output}. This is just a
* trivial wrapper around {@link #writeTo(CodedOutputStream)}. This does
* not flush or close the stream.
* <p>
* NOTE: Protocol Buffers are not self-delimiting. Therefore, if you write
* any more data to the stream after the message, you must somehow ensure
* that the parser on the receiving end does not interpret this as being
* part of the protocol message. This can be done e.g. by writing the size
* of the message before the data, then making sure to limit the input to
* that size on the receiving end (e.g. by wrapping the InputStream in one
* which limits the input). Alternatively, just use
* {@link #writeDelimitedTo(OutputStream)}.
*/
void writeTo(OutputStream output) throws IOException;
/**
* Like {@link #writeTo(OutputStream)}, but writes the size of the message
* as a varint before writing the data. This allows more data to be written
* to the stream after the message without the need to delimit the message
* data yourself. Use {@link Builder#mergeDelimitedFrom(InputStream)} (or
* the static method {@code YourMessageType.parseDelimitedFrom(InputStream)})
* to parse messages written by this method.
*/
void writeDelimitedTo(OutputStream output) throws IOException;
// =================================================================
// Builders
/**
* Constructs a new builder for a message of the same type as this message.
*/
// (From MessageLite, re-declared here only for return type covariance.)
Builder newBuilderForType();
/**
* Constructs a builder initialized with the current message. Use this to
* derive a new message from the current one.
*/
Builder toBuilder();
/**
* Abstract interface implemented by Protocol Message builders.
*/
public static interface Builder extends Cloneable {
/** Resets all fields to their default values. */
interface Builder extends MessageLite.Builder {
// (From MessageLite.Builder, re-declared here only for return type
// covariance.)
Builder clear();
/**
@ -244,71 +181,14 @@ public interface Message {
*/
Builder mergeFrom(Message other);
/**
* Construct the final message. Once this is called, the Builder is no
* longer valid, and calling any other method may throw a
* NullPointerException. If you need to continue working with the builder
* after calling {@code build()}, {@code clone()} it first.
* @throws UninitializedMessageException The message is missing one or more
* required fields (i.e. {@link #isInitialized()} returns false).
* Use {@link #buildPartial()} to bypass this check.
*/
// (From MessageLite.Builder, re-declared here only for return type
// covariance.)
Message build();
/**
* Like {@link #build()}, but does not throw an exception if the message
* is missing required fields. Instead, a partial message is returned.
*/
Message buildPartial();
/**
* Clones the Builder.
* @see Object#clone()
*/
Builder clone();
/**
* Returns true if all required fields in the message and all embedded
* messages are set, false otherwise.
*/
boolean isInitialized();
/**
* Parses a message of this type from the input and merges it with this
* message, as if using {@link Builder#mergeFrom(Message)}.
*
* <p>Warning: This does not verify that all required fields are present in
* the input message. If you call {@link #build()} without setting all
* required fields, it will throw an {@link UninitializedMessageException},
* which is a {@code RuntimeException} and thus might not be caught. There
* are a few good ways to deal with this:
* <ul>
* <li>Call {@link #isInitialized()} to verify that all required fields
* are set before building.
* <li>Parse the message separately using one of the static
* {@code parseFrom} methods, then use {@link #mergeFrom(Message)}
* to merge it with this one. {@code parseFrom} will throw an
* {@link InvalidProtocolBufferException} (an {@code IOException})
* if some required fields are missing.
* <li>Use {@code buildPartial()} to build, which ignores missing
* required fields.
* </ul>
*
* <p>Note: The caller should call
* {@link CodedInputStream#checkLastTagWas(int)} after calling this to
* verify that the last tag seen was the appropriate end-group tag,
* or zero for EOF.
*/
Builder mergeFrom(CodedInputStream input) throws IOException;
/**
* Like {@link Builder#mergeFrom(CodedInputStream)}, but also
* parses extensions. The extensions that you want to be able to parse
* must be registered in {@code extensionRegistry}. Extensions not in
* the registry will be treated as unknown fields.
*/
Builder mergeFrom(CodedInputStream input,
ExtensionRegistry extensionRegistry)
ExtensionRegistryLite extensionRegistry)
throws IOException;
/**
@ -317,10 +197,8 @@ public interface Message {
*/
Descriptors.Descriptor getDescriptorForType();
/**
* Get the message's type's default instance.
* See {@link Message#getDefaultInstanceForType()}.
*/
// (From MessageLite.Builder, re-declared here only for return type
// covariance.)
Message getDefaultInstanceForType();
/**
@ -399,92 +277,29 @@ public interface Message {
// ---------------------------------------------------------------
// Convenience methods.
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
// (From MessageLite.Builder, re-declared here only for return type
// covariance.)
Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
*/
Builder mergeFrom(ByteString data,
ExtensionRegistry extensionRegistry)
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
Builder mergeFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
public Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
public Builder mergeFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
*/
Builder mergeFrom(byte[] data,
ExtensionRegistry extensionRegistry)
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
*/
Builder mergeFrom(byte[] data, int off, int len,
ExtensionRegistry extensionRegistry)
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Parse a message of this type from {@code input} and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}. Note that this method always
* reads the <i>entire</i> input (unless it throws an exception). If you
* want it to stop earlier, you will need to wrap your input in some
* wrapper stream that limits reading. Or, use
* {@link Message#writeDelimitedTo(OutputStream)} to write your message and
* {@link #mergeDelimitedFrom(InputStream)} to read it.
* <p>
* Despite usually reading the entire input, this does not close the stream.
*/
Builder mergeFrom(InputStream input) throws IOException;
/**
* Parse a message of this type from {@code input} and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
*/
Builder mergeFrom(InputStream input,
ExtensionRegistry extensionRegistry)
ExtensionRegistryLite extensionRegistry)
throws IOException;
/**
* Like {@link #mergeFrom(InputStream)}, but does not read until EOF.
* Instead, the size of the message (encoded as a varint) is read first,
* then the message data. Use
* {@link Message#writeDelimitedTo(OutputStream)} to write messages in this
* format.
*/
Builder mergeDelimitedFrom(InputStream input)
throws IOException;
/**
* Like {@link #mergeDelimitedFrom(InputStream)} but supporting extensions.
*/
Builder mergeDelimitedFrom(InputStream input,
ExtensionRegistry extensionRegistry)
ExtensionRegistryLite extensionRegistry)
throws IOException;
}
}

View File

@ -0,0 +1,331 @@
// 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.
// TODO(kenton): Use generics? E.g. Builder<BuilderType extends Builder>, then
// mergeFrom*() could return BuilderType for better type-safety.
package com.google.protobuf;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Abstract interface implemented by Protocol Message objects.
*
* <p>This interface is implemented by all protocol message objects. Most
* users will be more interested in the Message interface, which is a subclass
* of MessageLite. Use MessageLite instead when you only need the subset of
* features which it supports -- namely, nothing that uses descriptors or
* reflection. You can instruct the protocol compiler to generate classes
* which implement only MessageLite, not the full Message interface, by adding
* the follow line to the .proto file:
* <pre>
* option optimize_for = LITE_RUNTIME;
* </pre>
*
* <p>This is particularly useful on resource-constrained systems where the
* full protocol buffers runtime library is too big.
*
* <p>Note that on non-constrained systems (e.g. servers) when you need to link
* in lots of protocol definitions, a better way to reduce total code footprint
* is to use {@code optimize_for = CODE_SIZE}. This will make the generated
* code smaller while still supporting all the same features (at the expense of
* speed). {@code optimize_for = LITE_RUNTIME} is best when you only have a
* small number of message types linked into your binary, in which case the
* size of the protocol buffers runtime itself is the biggest problem.
*
* @author kenton@google.com Kenton Varda
*/
public interface MessageLite {
/**
* 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();
/**
* Serializes the message and writes it to {@code output}. This does not
* flush or close the stream.
*/
void writeTo(CodedOutputStream output) throws IOException;
/**
* Get the number of bytes required to encode this message. The result
* is only computed on the first call and memoized after that.
*/
int getSerializedSize();
// -----------------------------------------------------------------
// Convenience methods.
/**
* Serializes the message to a {@code ByteString} and returns it. This is
* just a trivial wrapper around
* {@link #writeTo(CodedOutputStream)}.
*/
ByteString toByteString();
/**
* Serializes the message to a {@code byte} array and returns it. This is
* just a trivial wrapper around
* {@link #writeTo(CodedOutputStream)}.
*/
byte[] toByteArray();
/**
* Serializes the message and writes it to {@code output}. This is just a
* trivial wrapper around {@link #writeTo(CodedOutputStream)}. This does
* not flush or close the stream.
* <p>
* NOTE: Protocol Buffers are not self-delimiting. Therefore, if you write
* any more data to the stream after the message, you must somehow ensure
* that the parser on the receiving end does not interpret this as being
* part of the protocol message. This can be done e.g. by writing the size
* of the message before the data, then making sure to limit the input to
* that size on the receiving end (e.g. by wrapping the InputStream in one
* which limits the input). Alternatively, just use
* {@link #writeDelimitedTo(OutputStream)}.
*/
void writeTo(OutputStream output) throws IOException;
/**
* Like {@link #writeTo(OutputStream)}, but writes the size of the message
* as a varint before writing the data. This allows more data to be written
* to the stream after the message without the need to delimit the message
* data yourself. Use {@link Builder#mergeDelimitedFrom(InputStream)} (or
* the static method {@code YourMessageType.parseDelimitedFrom(InputStream)})
* to parse messages written by this method.
*/
void writeDelimitedTo(OutputStream output) throws IOException;
// =================================================================
// Builders
/**
* Constructs a new builder for a message of the same type as this message.
*/
Builder newBuilderForType();
/**
* Constructs a builder initialized with the current message. Use this to
* derive a new message from the current one.
*/
Builder toBuilder();
/**
* Abstract interface implemented by Protocol Message builders.
*/
interface Builder extends Cloneable {
/** Resets all fields to their default values. */
Builder clear();
/**
* Construct the final message. Once this is called, the Builder is no
* longer valid, and calling any other method will result in undefined
* behavior and may throw a NullPointerException. If you need to continue
* working with the builder after calling {@code build()}, {@code clone()}
* it first.
* @throws UninitializedMessageException The message is missing one or more
* required fields (i.e. {@link #isInitialized()} returns false).
* Use {@link #buildPartial()} to bypass this check.
*/
MessageLite build();
/**
* Like {@link #build()}, but does not throw an exception if the message
* is missing required fields. Instead, a partial message is returned.
* Once this is called, the Builder is no longer valid, and calling any
* will result in undefined behavior and may throw a NullPointerException.
*
* If you need to continue working with the builder after calling
* {@code buildPartial()}, {@code clone()} it first.
*/
MessageLite buildPartial();
/**
* Clones the Builder.
* @see Object#clone()
*/
Builder clone();
/**
* Returns true if all required fields in the message and all embedded
* messages are set, false otherwise.
*/
boolean isInitialized();
/**
* Parses a message of this type from the input and merges it with this
* message, as if using {@link Builder#mergeFrom(MessageLite)}.
*
* <p>Warning: This does not verify that all required fields are present in
* the input message. If you call {@link #build()} without setting all
* required fields, it will throw an {@link UninitializedMessageException},
* which is a {@code RuntimeException} and thus might not be caught. There
* are a few good ways to deal with this:
* <ul>
* <li>Call {@link #isInitialized()} to verify that all required fields
* are set before building.
* <li>Parse the message separately using one of the static
* {@code parseFrom} methods, then use {@link #mergeFrom(MessageLite)}
* to merge it with this one. {@code parseFrom} will throw an
* {@link InvalidProtocolBufferException} (an {@code IOException})
* if some required fields are missing.
* <li>Use {@code buildPartial()} to build, which ignores missing
* required fields.
* </ul>
*
* <p>Note: The caller should call
* {@link CodedInputStream#checkLastTagWas(int)} after calling this to
* verify that the last tag seen was the appropriate end-group tag,
* or zero for EOF.
*/
Builder mergeFrom(CodedInputStream input) throws IOException;
/**
* Like {@link Builder#mergeFrom(CodedInputStream)}, but also
* parses extensions. The extensions that you want to be able to parse
* must be registered in {@code extensionRegistry}. Extensions not in
* the registry will be treated as unknown fields.
*/
Builder mergeFrom(CodedInputStream input,
ExtensionRegistryLite extensionRegistry)
throws IOException;
/**
* Get the message's type's default instance.
* See {@link MessageLite#getDefaultInstanceForType()}.
*/
MessageLite getDefaultInstanceForType();
// ---------------------------------------------------------------
// Convenience methods.
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
*/
Builder mergeFrom(ByteString data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
Builder mergeFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
*/
Builder mergeFrom(byte[] data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
*/
Builder mergeFrom(byte[] data, int off, int len,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Parse a message of this type from {@code input} and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}. Note that this method always
* reads the <i>entire</i> input (unless it throws an exception). If you
* want it to stop earlier, you will need to wrap your input in some
* wrapper stream that limits reading. Or, use
* {@link MessageLite#writeDelimitedTo(OutputStream)} to write your message
* and {@link #mergeDelimitedFrom(InputStream)} to read it.
* <p>
* Despite usually reading the entire input, this does not close the stream.
*/
Builder mergeFrom(InputStream input) throws IOException;
/**
* Parse a message of this type from {@code input} and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
*/
Builder mergeFrom(InputStream input,
ExtensionRegistryLite extensionRegistry)
throws IOException;
/**
* Like {@link #mergeFrom(InputStream)}, but does not read until EOF.
* Instead, the size of the message (encoded as a varint) is read first,
* then the message data. Use
* {@link MessageLite#writeDelimitedTo(OutputStream)} to write messages in
* this format.
*/
Builder mergeDelimitedFrom(InputStream input)
throws IOException;
/**
* Like {@link #mergeDelimitedFrom(InputStream)} but supporting extensions.
*/
Builder mergeDelimitedFrom(InputStream input,
ExtensionRegistryLite extensionRegistry)
throws IOException;
}
}

View File

@ -37,7 +37,7 @@ import com.google.protobuf.Descriptors.EnumValueDescriptor;
* Interface of useful methods added to all enums generated by the protocol
* compiler.
*/
public interface ProtocolMessageEnum {
public interface ProtocolMessageEnum extends Internal.EnumLite {
/**
* Return the value's numeric value as defined in the .proto file.

View File

@ -71,11 +71,11 @@ public final class RpcUtil {
final Class<Type> originalClass,
final Type defaultInstance) {
return new RpcCallback<Message>() {
public void run(Message parameter) {
public void run(final Message parameter) {
Type typedParameter;
try {
typedParameter = originalClass.cast(parameter);
} catch (ClassCastException e) {
} catch (ClassCastException ignored) {
typedParameter = copyAsType(defaultInstance, parameter);
}
originalCallback.run(typedParameter);
@ -90,7 +90,7 @@ public final class RpcUtil {
*/
@SuppressWarnings("unchecked")
private static <Type extends Message> Type copyAsType(
Type typeDefaultInstance, Message source) {
final Type typeDefaultInstance, final Message source) {
return (Type)typeDefaultInstance.newBuilderForType()
.mergeFrom(source)
.build();
@ -106,8 +106,9 @@ public final class RpcUtil {
RpcCallback<ParameterType> newOneTimeCallback(
final RpcCallback<ParameterType> originalCallback) {
return new RpcCallback<ParameterType>() {
boolean alreadyCalled = false;
public void run(ParameterType parameter) {
private boolean alreadyCalled = false;
public void run(final ParameterType parameter) {
synchronized(this) {
if (alreadyCalled) {
throw new AlreadyCalledException();
@ -124,6 +125,8 @@ public final class RpcUtil {
* Exception thrown when a one-time callback is called more than once.
*/
public static final class AlreadyCalledException extends RuntimeException {
private static final long serialVersionUID = 5469741279507848266L;
public AlreadyCalledException() {
super("This RpcCallback was already called and cannot be called " +
"multiple times.");

View File

@ -32,11 +32,13 @@ package com.google.protobuf;
/**
* Thrown by blocking RPC methods when a failure occurs.
*
*
* @author cpovirk@google.com (Chris Povirk)
*/
public final class ServiceException extends Exception {
public ServiceException(String message) {
private static final long serialVersionUID = -1219262335729891920L;
public ServiceException(final String message) {
super(message);
}
}

View File

@ -52,22 +52,25 @@ import java.util.regex.Pattern;
* @author kenton@google.com Kenton Varda
*/
public final class TextFormat {
private TextFormat() {
}
/**
* Outputs a textual representation of the Protocol Message supplied into
* the parameter output. (This representation is the new version of the
* classic "ProtocolPrinter" output from the original Protocol Buffer system)
*/
public static void print(Message message, Appendable output)
public static void print(final Message message, final Appendable output)
throws IOException {
TextGenerator generator = new TextGenerator(output);
final TextGenerator generator = new TextGenerator(output);
print(message, generator);
}
/** Outputs a textual representation of {@code fields} to {@code output}. */
public static void print(UnknownFieldSet fields, Appendable output)
public static void print(final UnknownFieldSet fields,
final Appendable output)
throws IOException {
TextGenerator generator = new TextGenerator(output);
final TextGenerator generator = new TextGenerator(output);
printUnknownFields(fields, generator);
}
@ -75,9 +78,9 @@ public final class TextFormat {
* Like {@code print()}, but writes directly to a {@code String} and
* returns it.
*/
public static String printToString(Message message) {
public static String printToString(final Message message) {
try {
StringBuilder text = new StringBuilder();
final StringBuilder text = new StringBuilder();
print(message, text);
return text.toString();
} catch (IOException e) {
@ -91,9 +94,9 @@ public final class TextFormat {
* Like {@code print()}, but writes directly to a {@code String} and
* returns it.
*/
public static String printToString(UnknownFieldSet fields) {
public static String printToString(final UnknownFieldSet fields) {
try {
StringBuilder text = new StringBuilder();
final StringBuilder text = new StringBuilder();
print(fields, text);
return text.toString();
} catch (IOException e) {
@ -103,22 +106,44 @@ public final class TextFormat {
}
}
private static void print(Message message, TextGenerator generator)
private static void print(final Message message,
final TextGenerator generator)
throws IOException {
for (Map.Entry<FieldDescriptor, Object> field :
for (final Map.Entry<FieldDescriptor, Object> field :
message.getAllFields().entrySet()) {
printField(field.getKey(), field.getValue(), generator);
}
printUnknownFields(message.getUnknownFields(), generator);
}
public static void printField(final FieldDescriptor field,
final Object value,
final Appendable output)
throws IOException {
final TextGenerator generator = new TextGenerator(output);
printField(field, value, generator);
}
public static void printField(FieldDescriptor field,
Object value,
TextGenerator generator)
public static String printFieldToString(final FieldDescriptor field,
final Object value) {
try {
final StringBuilder text = new StringBuilder();
printField(field, value, text);
return text.toString();
} catch (IOException e) {
throw new RuntimeException(
"Writing to a StringBuilder threw an IOException (should never " +
"happen).", e);
}
}
private static void printField(final FieldDescriptor field,
final Object value,
final TextGenerator generator)
throws IOException {
if (field.isRepeated()) {
// Repeated field. Print each element.
for (Object element : (List) value) {
for (final Object element : (List) value) {
printSingleField(field, element, generator);
}
} else {
@ -126,9 +151,9 @@ public final class TextFormat {
}
}
private static void printSingleField(FieldDescriptor field,
Object value,
TextGenerator generator)
private static void printSingleField(final FieldDescriptor field,
final Object value,
final TextGenerator generator)
throws IOException {
if (field.isExtension()) {
generator.print("[");
@ -168,9 +193,9 @@ public final class TextFormat {
generator.print("\n");
}
private static void printFieldValue(FieldDescriptor field,
Object value,
TextGenerator generator)
private static void printFieldValue(final FieldDescriptor field,
final Object value,
final TextGenerator generator)
throws IOException {
switch (field.getType()) {
case INT32:
@ -202,17 +227,15 @@ public final class TextFormat {
generator.print("\"");
break;
case BYTES: {
case BYTES:
generator.print("\"");
generator.print(escapeBytes((ByteString) value));
generator.print("\"");
break;
}
case ENUM: {
case ENUM:
generator.print(((EnumValueDescriptor) value).getName());
break;
}
case MESSAGE:
case GROUP:
@ -221,39 +244,39 @@ public final class TextFormat {
}
}
private static void printUnknownFields(UnknownFieldSet unknownFields,
TextGenerator generator)
private static void printUnknownFields(final UnknownFieldSet unknownFields,
final TextGenerator generator)
throws IOException {
for (Map.Entry<Integer, UnknownFieldSet.Field> entry :
for (final Map.Entry<Integer, UnknownFieldSet.Field> entry :
unknownFields.asMap().entrySet()) {
String prefix = entry.getKey().toString() + ": ";
UnknownFieldSet.Field field = entry.getValue();
final String prefix = entry.getKey().toString() + ": ";
final UnknownFieldSet.Field field = entry.getValue();
for (long value : field.getVarintList()) {
for (final long value : field.getVarintList()) {
generator.print(entry.getKey().toString());
generator.print(": ");
generator.print(unsignedToString(value));
generator.print("\n");
}
for (int value : field.getFixed32List()) {
for (final int value : field.getFixed32List()) {
generator.print(entry.getKey().toString());
generator.print(": ");
generator.print(String.format((Locale) null, "0x%08x", value));
generator.print("\n");
}
for (long value : field.getFixed64List()) {
for (final long value : field.getFixed64List()) {
generator.print(entry.getKey().toString());
generator.print(": ");
generator.print(String.format((Locale) null, "0x%016x", value));
generator.print("\n");
}
for (ByteString value : field.getLengthDelimitedList()) {
for (final ByteString value : field.getLengthDelimitedList()) {
generator.print(entry.getKey().toString());
generator.print(": \"");
generator.print(escapeBytes(value));
generator.print("\"\n");
}
for (UnknownFieldSet value : field.getGroupList()) {
for (final UnknownFieldSet value : field.getGroupList()) {
generator.print(entry.getKey().toString());
generator.print(" {\n");
generator.indent();
@ -265,7 +288,7 @@ public final class TextFormat {
}
/** Convert an unsigned 32-bit integer to a string. */
private static String unsignedToString(int value) {
private static String unsignedToString(final int value) {
if (value >= 0) {
return Integer.toString(value);
} else {
@ -274,7 +297,7 @@ public final class TextFormat {
}
/** Convert an unsigned 64-bit integer to a string. */
private static String unsignedToString(long value) {
private static String unsignedToString(final long value) {
if (value >= 0) {
return Long.toString(value);
} else {
@ -288,13 +311,12 @@ public final class TextFormat {
/**
* An inner class for writing text to the output stream.
*/
static private final class TextGenerator {
private static final class TextGenerator {
private Appendable output;
private boolean atStartOfLine = true;
private final StringBuilder indent = new StringBuilder();
Appendable output;
boolean atStartOfLine = true;
StringBuilder indent = new StringBuilder();
public TextGenerator(Appendable output) {
private TextGenerator(final Appendable output) {
this.output = output;
}
@ -312,7 +334,7 @@ public final class TextFormat {
* level is zero.
*/
public void outdent() {
int length = indent.length();
final int length = indent.length();
if (length == 0) {
throw new IllegalArgumentException(
" Outdent() without matching Indent().");
@ -323,8 +345,8 @@ public final class TextFormat {
/**
* Print text to the output stream.
*/
public void print(CharSequence text) throws IOException {
int size = text.length();
public void print(final CharSequence text) throws IOException {
final int size = text.length();
int pos = 0;
for (int i = 0; i < size; i++) {
@ -337,7 +359,8 @@ public final class TextFormat {
write(text.subSequence(pos, size), size - pos);
}
private void write(CharSequence data, int size) throws IOException {
private void write(final CharSequence data, final int size)
throws IOException {
if (size == 0) {
return;
}
@ -399,27 +422,27 @@ public final class TextFormat {
// We use possesive quantifiers (*+ and ++) because otherwise the Java
// regex matcher has stack overflows on large inputs.
private static Pattern WHITESPACE =
private static final Pattern WHITESPACE =
Pattern.compile("(\\s|(#.*$))++", Pattern.MULTILINE);
private static Pattern TOKEN = Pattern.compile(
private static final Pattern TOKEN = Pattern.compile(
"[a-zA-Z_][0-9a-zA-Z_+-]*+|" + // an identifier
"[0-9+-][0-9a-zA-Z_.+-]*+|" + // a number
"\"([^\"\n\\\\]|\\\\.)*+(\"|\\\\?$)|" + // a double-quoted string
"\'([^\"\n\\\\]|\\\\.)*+(\'|\\\\?$)", // a single-quoted string
Pattern.MULTILINE);
private static Pattern DOUBLE_INFINITY = Pattern.compile(
private static final Pattern DOUBLE_INFINITY = Pattern.compile(
"-?inf(inity)?",
Pattern.CASE_INSENSITIVE);
private static Pattern FLOAT_INFINITY = Pattern.compile(
private static final Pattern FLOAT_INFINITY = Pattern.compile(
"-?inf(inity)?f?",
Pattern.CASE_INSENSITIVE);
private static Pattern FLOAT_NAN = Pattern.compile(
private static final Pattern FLOAT_NAN = Pattern.compile(
"nanf?",
Pattern.CASE_INSENSITIVE);
/** Construct a tokenizer that parses tokens from the given text. */
public Tokenizer(CharSequence text) {
private Tokenizer(final CharSequence text) {
this.text = text;
this.matcher = WHITESPACE.matcher(text);
skipWhitespace();
@ -481,7 +504,7 @@ public final class TextFormat {
* If the next token exactly matches {@code token}, consume it and return
* {@code true}. Otherwise, return {@code false} without doing anything.
*/
public boolean tryConsume(String token) {
public boolean tryConsume(final String token) {
if (currentToken.equals(token)) {
nextToken();
return true;
@ -494,7 +517,7 @@ public final class TextFormat {
* If the next token exactly matches {@code token}, consume it. Otherwise,
* throw a {@link ParseException}.
*/
public void consume(String token) throws ParseException {
public void consume(final String token) throws ParseException {
if (!tryConsume(token)) {
throw parseException("Expected \"" + token + "\".");
}
@ -509,7 +532,7 @@ public final class TextFormat {
return false;
}
char c = currentToken.charAt(0);
final char c = currentToken.charAt(0);
return ('0' <= c && c <= '9') ||
c == '-' || c == '+';
}
@ -520,7 +543,7 @@ public final class TextFormat {
*/
public String consumeIdentifier() throws ParseException {
for (int i = 0; i < currentToken.length(); i++) {
char c = currentToken.charAt(i);
final char c = currentToken.charAt(i);
if (('a' <= c && c <= 'z') ||
('A' <= c && c <= 'Z') ||
('0' <= c && c <= '9') ||
@ -531,7 +554,7 @@ public final class TextFormat {
}
}
String result = currentToken;
final String result = currentToken;
nextToken();
return result;
}
@ -542,7 +565,7 @@ public final class TextFormat {
*/
public int consumeInt32() throws ParseException {
try {
int result = parseInt32(currentToken);
final int result = parseInt32(currentToken);
nextToken();
return result;
} catch (NumberFormatException e) {
@ -556,7 +579,7 @@ public final class TextFormat {
*/
public int consumeUInt32() throws ParseException {
try {
int result = parseUInt32(currentToken);
final int result = parseUInt32(currentToken);
nextToken();
return result;
} catch (NumberFormatException e) {
@ -570,7 +593,7 @@ public final class TextFormat {
*/
public long consumeInt64() throws ParseException {
try {
long result = parseInt64(currentToken);
final long result = parseInt64(currentToken);
nextToken();
return result;
} catch (NumberFormatException e) {
@ -584,7 +607,7 @@ public final class TextFormat {
*/
public long consumeUInt64() throws ParseException {
try {
long result = parseUInt64(currentToken);
final long result = parseUInt64(currentToken);
nextToken();
return result;
} catch (NumberFormatException e) {
@ -600,7 +623,7 @@ public final class TextFormat {
// We need to parse infinity and nan separately because
// Double.parseDouble() does not accept "inf", "infinity", or "nan".
if (DOUBLE_INFINITY.matcher(currentToken).matches()) {
boolean negative = currentToken.startsWith("-");
final boolean negative = currentToken.startsWith("-");
nextToken();
return negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
}
@ -609,7 +632,7 @@ public final class TextFormat {
return Double.NaN;
}
try {
double result = Double.parseDouble(currentToken);
final double result = Double.parseDouble(currentToken);
nextToken();
return result;
} catch (NumberFormatException e) {
@ -625,7 +648,7 @@ public final class TextFormat {
// We need to parse infinity and nan separately because
// Float.parseFloat() does not accept "inf", "infinity", or "nan".
if (FLOAT_INFINITY.matcher(currentToken).matches()) {
boolean negative = currentToken.startsWith("-");
final boolean negative = currentToken.startsWith("-");
nextToken();
return negative ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
}
@ -634,7 +657,7 @@ public final class TextFormat {
return Float.NaN;
}
try {
float result = Float.parseFloat(currentToken);
final float result = Float.parseFloat(currentToken);
nextToken();
return result;
} catch (NumberFormatException e) {
@ -672,7 +695,8 @@ public final class TextFormat {
* {@link ParseException}.
*/
public ByteString consumeByteString() throws ParseException {
char quote = currentToken.length() > 0 ? currentToken.charAt(0) : '\0';
final char quote = currentToken.length() > 0 ? currentToken.charAt(0)
: '\0';
if (quote != '\"' && quote != '\'') {
throw parseException("Expected string.");
}
@ -683,11 +707,12 @@ public final class TextFormat {
}
try {
String escaped = currentToken.substring(1, currentToken.length() - 1);
ByteString result = unescapeBytes(escaped);
final String escaped =
currentToken.substring(1, currentToken.length() - 1);
final ByteString result = unescapeBytes(escaped);
nextToken();
return result;
} catch (InvalidEscapeSequence e) {
} catch (InvalidEscapeSequenceException e) {
throw parseException(e.getMessage());
}
}
@ -696,7 +721,7 @@ public final class TextFormat {
* Returns a {@link ParseException} with the current line and column
* numbers in the description, suitable for throwing.
*/
public ParseException parseException(String description) {
public ParseException parseException(final String description) {
// Note: People generally prefer one-based line and column numbers.
return new ParseException(
(line + 1) + ":" + (column + 1) + ": " + description);
@ -706,7 +731,8 @@ public final class TextFormat {
* Returns a {@link ParseException} with the line and column numbers of
* the previous token in the description, suitable for throwing.
*/
public ParseException parseExceptionPreviousToken(String description) {
public ParseException parseExceptionPreviousToken(
final String description) {
// Note: People generally prefer one-based line and column numbers.
return new ParseException(
(previousLine + 1) + ":" + (previousColumn + 1) + ": " + description);
@ -716,7 +742,8 @@ public final class TextFormat {
* Constructs an appropriate {@link ParseException} for the given
* {@code NumberFormatException} when trying to parse an integer.
*/
private ParseException integerParseException(NumberFormatException e) {
private ParseException integerParseException(
final NumberFormatException e) {
return parseException("Couldn't parse integer: " + e.getMessage());
}
@ -724,14 +751,16 @@ public final class TextFormat {
* Constructs an appropriate {@link ParseException} for the given
* {@code NumberFormatException} when trying to parse a float or double.
*/
private ParseException floatParseException(NumberFormatException e) {
private ParseException floatParseException(final NumberFormatException e) {
return parseException("Couldn't parse number: " + e.getMessage());
}
}
/** Thrown when parsing an invalid text format message. */
public static class ParseException extends IOException {
public ParseException(String message) {
private static final long serialVersionUID = 3196188060225107702L;
public ParseException(final String message) {
super(message);
}
}
@ -740,9 +769,9 @@ public final class TextFormat {
* Parse a text-format message from {@code input} and merge the contents
* into {@code builder}.
*/
public static void merge(Readable input,
Message.Builder builder)
throws ParseException, IOException {
public static void merge(final Readable input,
final Message.Builder builder)
throws IOException {
merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
}
@ -750,8 +779,8 @@ public final class TextFormat {
* Parse a text-format message from {@code input} and merge the contents
* into {@code builder}.
*/
public static void merge(CharSequence input,
Message.Builder builder)
public static void merge(final CharSequence input,
final Message.Builder builder)
throws ParseException {
merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
}
@ -761,10 +790,10 @@ public final class TextFormat {
* into {@code builder}. Extensions will be recognized if they are
* registered in {@code extensionRegistry}.
*/
public static void merge(Readable input,
ExtensionRegistry extensionRegistry,
Message.Builder builder)
throws ParseException, IOException {
public static void merge(final Readable input,
final ExtensionRegistry extensionRegistry,
final Message.Builder builder)
throws IOException {
// Read the entire input to a String then parse that.
// If StreamTokenizer were not quite so crippled, or if there were a kind
@ -780,12 +809,12 @@ public final class TextFormat {
// TODO(chrisn): See if working around java.io.Reader#read(CharBuffer)
// overhead is worthwhile
private static StringBuilder toStringBuilder(Readable input)
private static StringBuilder toStringBuilder(final Readable input)
throws IOException {
StringBuilder text = new StringBuilder();
CharBuffer buffer = CharBuffer.allocate(BUFFER_SIZE);
final StringBuilder text = new StringBuilder();
final CharBuffer buffer = CharBuffer.allocate(BUFFER_SIZE);
while (true) {
int n = input.read(buffer);
final int n = input.read(buffer);
if (n == -1) {
break;
}
@ -800,11 +829,11 @@ public final class TextFormat {
* into {@code builder}. Extensions will be recognized if they are
* registered in {@code extensionRegistry}.
*/
public static void merge(CharSequence input,
ExtensionRegistry extensionRegistry,
Message.Builder builder)
public static void merge(final CharSequence input,
final ExtensionRegistry extensionRegistry,
final Message.Builder builder)
throws ParseException {
Tokenizer tokenizer = new Tokenizer(input);
final Tokenizer tokenizer = new Tokenizer(input);
while (!tokenizer.atEnd()) {
mergeField(tokenizer, extensionRegistry, builder);
@ -815,19 +844,20 @@ public final class TextFormat {
* Parse a single field from {@code tokenizer} and merge it into
* {@code builder}.
*/
private static void mergeField(Tokenizer tokenizer,
ExtensionRegistry extensionRegistry,
Message.Builder builder)
private static void mergeField(final Tokenizer tokenizer,
final ExtensionRegistry extensionRegistry,
final Message.Builder builder)
throws ParseException {
FieldDescriptor field;
Descriptor type = builder.getDescriptorForType();
final Descriptor type = builder.getDescriptorForType();
ExtensionRegistry.ExtensionInfo extension = null;
if (tokenizer.tryConsume("[")) {
// An extension.
StringBuilder name = new StringBuilder(tokenizer.consumeIdentifier());
final StringBuilder name =
new StringBuilder(tokenizer.consumeIdentifier());
while (tokenizer.tryConsume(".")) {
name.append(".");
name.append('.');
name.append(tokenizer.consumeIdentifier());
}
@ -846,7 +876,7 @@ public final class TextFormat {
field = extension.descriptor;
} else {
String name = tokenizer.consumeIdentifier();
final String name = tokenizer.consumeIdentifier();
field = type.findFieldByName(name);
// Group names are expected to be capitalized as they appear in the
@ -855,7 +885,7 @@ public final class TextFormat {
if (field == null) {
// Explicitly specify US locale so that this code does not break when
// executing in Turkey.
String lowerName = name.toLowerCase(Locale.US);
final String lowerName = name.toLowerCase(Locale.US);
field = type.findFieldByName(lowerName);
// If the case-insensitive match worked but the field is NOT a group,
if (field != null && field.getType() != FieldDescriptor.Type.GROUP) {
@ -880,7 +910,7 @@ public final class TextFormat {
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
tokenizer.tryConsume(":"); // optional
String endToken;
final String endToken;
if (tokenizer.tryConsume("<")) {
endToken = ">";
} else {
@ -888,7 +918,7 @@ public final class TextFormat {
endToken = "}";
}
Message.Builder subBuilder;
final Message.Builder subBuilder;
if (extension == null) {
subBuilder = builder.newBuilderForField(field);
} else {
@ -951,19 +981,19 @@ public final class TextFormat {
value = tokenizer.consumeByteString();
break;
case ENUM: {
EnumDescriptor enumType = field.getEnumType();
case ENUM:
final EnumDescriptor enumType = field.getEnumType();
if (tokenizer.lookingAtInteger()) {
int number = tokenizer.consumeInt32();
final int number = tokenizer.consumeInt32();
value = enumType.findValueByNumber(number);
if (value == null) {
throw tokenizer.parseExceptionPreviousToken(
"Enum type \"" + enumType.getFullName() +
"\" has no value with number " + number + ".");
"\" has no value with number " + number + '.');
}
} else {
String id = tokenizer.consumeIdentifier();
final String id = tokenizer.consumeIdentifier();
value = enumType.findValueByName(id);
if (value == null) {
throw tokenizer.parseExceptionPreviousToken(
@ -973,7 +1003,6 @@ public final class TextFormat {
}
break;
}
case MESSAGE:
case GROUP:
@ -1002,10 +1031,10 @@ public final class TextFormat {
* which no defined short-hand escape sequence is defined will be escaped
* using 3-digit octal sequences.
*/
static String escapeBytes(ByteString input) {
StringBuilder builder = new StringBuilder(input.size());
static String escapeBytes(final ByteString input) {
final StringBuilder builder = new StringBuilder(input.size());
for (int i = 0; i < input.size(); i++) {
byte b = input.byteAt(i);
final byte b = input.byteAt(i);
switch (b) {
// Java does not recognize \a or \v, apparently.
case 0x07: builder.append("\\a" ); break;
@ -1038,9 +1067,9 @@ public final class TextFormat {
* {@link #escapeBytes(ByteString)}. Two-digit hex escapes (starting with
* "\x") are also recognized.
*/
static ByteString unescapeBytes(CharSequence input)
throws InvalidEscapeSequence {
byte[] result = new byte[input.length()];
static ByteString unescapeBytes(final CharSequence input)
throws InvalidEscapeSequenceException {
final byte[] result = new byte[input.length()];
int pos = 0;
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
@ -1080,7 +1109,7 @@ public final class TextFormat {
++i;
code = digitValue(input.charAt(i));
} else {
throw new InvalidEscapeSequence(
throw new InvalidEscapeSequenceException(
"Invalid escape sequence: '\\x' with no digits");
}
if (i + 1 < input.length() && isHex(input.charAt(i + 1))) {
@ -1091,12 +1120,12 @@ public final class TextFormat {
break;
default:
throw new InvalidEscapeSequence(
"Invalid escape sequence: '\\" + c + "'");
throw new InvalidEscapeSequenceException(
"Invalid escape sequence: '\\" + c + '\'');
}
}
} else {
throw new InvalidEscapeSequence(
throw new InvalidEscapeSequenceException(
"Invalid escape sequence: '\\' at end of string.");
}
} else {
@ -1111,8 +1140,10 @@ public final class TextFormat {
* Thrown by {@link TextFormat#unescapeBytes} and
* {@link TextFormat#unescapeText} when an invalid escape sequence is seen.
*/
static class InvalidEscapeSequence extends IOException {
public InvalidEscapeSequence(String description) {
static class InvalidEscapeSequenceException extends IOException {
private static final long serialVersionUID = -8164033650142593304L;
InvalidEscapeSequenceException(final String description) {
super(description);
}
}
@ -1122,7 +1153,7 @@ public final class TextFormat {
* Non-ASCII characters are first encoded as UTF-8, then each byte is escaped
* individually as a 3-digit octal escape. Yes, it's weird.
*/
static String escapeText(String input) {
static String escapeText(final String input) {
return escapeBytes(ByteString.copyFromUtf8(input));
}
@ -1130,17 +1161,18 @@ public final class TextFormat {
* Un-escape a text string as escaped using {@link #escapeText(String)}.
* Two-digit hex escapes (starting with "\x") are also recognized.
*/
static String unescapeText(String input) throws InvalidEscapeSequence {
static String unescapeText(final String input)
throws InvalidEscapeSequenceException {
return unescapeBytes(input).toStringUtf8();
}
/** Is this an octal digit? */
private static boolean isOctal(char c) {
private static boolean isOctal(final char c) {
return '0' <= c && c <= '7';
}
/** Is this a hex digit? */
private static boolean isHex(char c) {
private static boolean isHex(final char c) {
return ('0' <= c && c <= '9') ||
('a' <= c && c <= 'f') ||
('A' <= c && c <= 'F');
@ -1151,7 +1183,7 @@ public final class TextFormat {
* numeric value. This is like {@code Character.digit()} but we don't accept
* non-ASCII digits.
*/
private static int digitValue(char c) {
private static int digitValue(final char c) {
if ('0' <= c && c <= '9') {
return c - '0';
} else if ('a' <= c && c <= 'z') {
@ -1166,7 +1198,7 @@ public final class TextFormat {
* {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
* and "0" to signify hexidecimal and octal numbers, respectively.
*/
static int parseInt32(String text) throws NumberFormatException {
static int parseInt32(final String text) throws NumberFormatException {
return (int) parseInteger(text, true, false);
}
@ -1177,7 +1209,7 @@ public final class TextFormat {
* result is coerced to a (signed) {@code int} when returned since Java has
* no unsigned integer type.
*/
static int parseUInt32(String text) throws NumberFormatException {
static int parseUInt32(final String text) throws NumberFormatException {
return (int) parseInteger(text, false, false);
}
@ -1186,7 +1218,7 @@ public final class TextFormat {
* {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
* and "0" to signify hexidecimal and octal numbers, respectively.
*/
static long parseInt64(String text) throws NumberFormatException {
static long parseInt64(final String text) throws NumberFormatException {
return parseInteger(text, true, true);
}
@ -1197,13 +1229,13 @@ public final class TextFormat {
* result is coerced to a (signed) {@code long} when returned since Java has
* no unsigned long type.
*/
static long parseUInt64(String text) throws NumberFormatException {
static long parseUInt64(final String text) throws NumberFormatException {
return parseInteger(text, false, true);
}
private static long parseInteger(String text,
boolean isSigned,
boolean isLong)
private static long parseInteger(final String text,
final boolean isSigned,
final boolean isLong)
throws NumberFormatException {
int pos = 0;
@ -1224,7 +1256,7 @@ public final class TextFormat {
radix = 8;
}
String numberText = text.substring(pos);
final String numberText = text.substring(pos);
long result = 0;
if (numberText.length() < 16) {

View File

@ -30,12 +30,8 @@
package com.google.protobuf;
import com.google.protobuf.Descriptors.FieldDescriptor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Thrown when attempting to build a protocol message that is missing required
@ -51,11 +47,15 @@ import java.util.Map;
* @author kenton@google.com Kenton Varda
*/
public class UninitializedMessageException extends RuntimeException {
public UninitializedMessageException(Message message) {
this(findMissingFields(message));
private static final long serialVersionUID = -7466929953374883507L;
public UninitializedMessageException(final MessageLite message) {
super("Message was missing required fields. (Lite runtime could not " +
"determine which fields were missing).");
missingFields = null;
}
private UninitializedMessageException(List<String> missingFields) {
public UninitializedMessageException(final List<String> missingFields) {
super(buildDescription(missingFields));
this.missingFields = missingFields;
}
@ -65,6 +65,8 @@ public class UninitializedMessageException extends RuntimeException {
/**
* Get a list of human-readable names of required fields missing from this
* message. Each name is a full path to a field, e.g. "foo.bar[5].baz".
* Returns null if the lite runtime was used, since it lacks the ability to
* find missing fields.
*/
public List<String> getMissingFields() {
return Collections.unmodifiableList(missingFields);
@ -80,11 +82,11 @@ public class UninitializedMessageException extends RuntimeException {
}
/** Construct the description string for this exception. */
private static String buildDescription(List<String> missingFields) {
StringBuilder description =
private static String buildDescription(final List<String> missingFields) {
final StringBuilder description =
new StringBuilder("Message missing required fields: ");
boolean first = true;
for (String field : missingFields) {
for (final String field : missingFields) {
if (first) {
first = false;
} else {
@ -94,67 +96,4 @@ public class UninitializedMessageException extends RuntimeException {
}
return description.toString();
}
/**
* Populates {@code this.missingFields} with the full "path" of each
* missing required field in the given message.
*/
private static List<String> findMissingFields(Message message) {
List<String> results = new ArrayList<String>();
findMissingFields(message, "", results);
return results;
}
/** Recursive helper implementing {@link #findMissingFields(Message)}. */
private static void findMissingFields(Message message, String prefix,
List<String> results) {
for (FieldDescriptor field : message.getDescriptorForType().getFields()) {
if (field.isRequired() && !message.hasField(field)) {
results.add(prefix + field.getName());
}
}
for (Map.Entry<FieldDescriptor, Object> entry :
message.getAllFields().entrySet()) {
FieldDescriptor field = entry.getKey();
Object value = entry.getValue();
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
if (field.isRepeated()) {
int i = 0;
for (Object element : (List) value) {
findMissingFields((Message) element,
subMessagePrefix(prefix, field, i++),
results);
}
} else {
if (message.hasField(field)) {
findMissingFields((Message) value,
subMessagePrefix(prefix, field, -1),
results);
}
}
}
}
}
private static String subMessagePrefix(String prefix,
FieldDescriptor field,
int index) {
StringBuilder result = new StringBuilder(prefix);
if (field.isExtension()) {
result.append('(')
.append(field.getFullName())
.append(')');
} else {
result.append(field.getName());
}
if (index != -1) {
result.append('[')
.append(index)
.append(']');
}
result.append('.');
return result.toString();
}
}

View File

@ -30,15 +30,17 @@
package com.google.protobuf;
import java.io.InputStream;
import com.google.protobuf.Internal.ThreadLocalQuickQueue;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.TreeMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* {@code UnknownFieldSet} is used to keep track of fields which were seen when
@ -48,56 +50,59 @@ import java.util.Map;
* compiled before the new types were added.
*
* <p>Every {@link Message} contains an {@code UnknownFieldSet} (and every
* {@link Message.Builder} contains an {@link UnknownFieldSet.Builder}).
* {@link Message.Builder} contains an {@link Builder}).
*
* <p>Most users will never need to use this class.
*
* @author kenton@google.com Kenton Varda
*/
public final class UnknownFieldSet {
public final class UnknownFieldSet implements MessageLite {
private UnknownFieldSet() {}
/** Create a new {@link UnknownFieldSet.Builder}. */
/** Create a new {@link Builder}. */
public static Builder newBuilder() {
return new Builder();
return Builder.create();
}
/**
* Create a new {@link UnknownFieldSet.Builder} and initialize it to be a copy
* Create a new {@link Builder} and initialize it to be a copy
* of {@code copyFrom}.
*/
public static Builder newBuilder(UnknownFieldSet copyFrom) {
return new Builder().mergeFrom(copyFrom);
public static Builder newBuilder(final UnknownFieldSet copyFrom) {
return newBuilder().mergeFrom(copyFrom);
}
/** Get an empty {@code UnknownFieldSet}. */
public static UnknownFieldSet getDefaultInstance() {
return defaultInstance;
}
private static UnknownFieldSet defaultInstance =
public UnknownFieldSet getDefaultInstanceForType() {
return defaultInstance;
}
private static final UnknownFieldSet defaultInstance =
new UnknownFieldSet(Collections.<Integer, Field>emptyMap());
/**
* Construct an {@code UnknownFieldSet} around the given map. The map is
* expected to be immutable.
*/
private UnknownFieldSet(Map<Integer, Field> fields) {
private UnknownFieldSet(final Map<Integer, Field> fields) {
this.fields = fields;
}
private Map<Integer, Field> fields;
@Override
public boolean equals(Object other) {
public boolean equals(final Object other) {
if (this == other) {
return true;
}
return (other instanceof UnknownFieldSet) &&
this.fields.equals(((UnknownFieldSet) other).fields);
fields.equals(((UnknownFieldSet) other).fields);
}
@Override
public int hashCode() {
return this.fields.hashCode();
return fields.hashCode();
}
/** Get a map of fields in the set by number. */
@ -106,7 +111,7 @@ public final class UnknownFieldSet {
}
/** Check if the given field number is present in the set. */
public boolean hasField(int number) {
public boolean hasField(final int number) {
return fields.containsKey(number);
}
@ -114,14 +119,14 @@ public final class UnknownFieldSet {
* Get a field by number. Returns an empty field if not present. Never
* returns {@code null}.
*/
public Field getField(int number) {
Field result = fields.get(number);
public Field getField(final int number) {
final Field result = fields.get(number);
return (result == null) ? Field.getDefaultInstance() : result;
}
/** Serializes the set and writes it to {@code output}. */
public void writeTo(CodedOutputStream output) throws IOException {
for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
public void writeTo(final CodedOutputStream output) throws IOException {
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
entry.getValue().writeTo(entry.getKey(), output);
}
}
@ -131,7 +136,8 @@ public final class UnknownFieldSet {
* just a trivial wrapper around
* {@link TextFormat#printToString(UnknownFieldSet)}.
*/
public final String toString() {
@Override
public String toString() {
return TextFormat.printToString(this);
}
@ -139,13 +145,13 @@ public final class UnknownFieldSet {
* Serializes the message to a {@code ByteString} and returns it. This is
* just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
*/
public final ByteString toByteString() {
public ByteString toByteString() {
try {
ByteString.CodedBuilder out =
final ByteString.CodedBuilder out =
ByteString.newCodedBuilder(getSerializedSize());
writeTo(out.getCodedOutput());
return out.build();
} catch (IOException e) {
} catch (final IOException e) {
throw new RuntimeException(
"Serializing to a ByteString threw an IOException (should " +
"never happen).", e);
@ -156,14 +162,14 @@ public final class UnknownFieldSet {
* Serializes the message to a {@code byte} array and returns it. This is
* just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
*/
public final byte[] toByteArray() {
public byte[] toByteArray() {
try {
byte[] result = new byte[getSerializedSize()];
CodedOutputStream output = CodedOutputStream.newInstance(result);
final byte[] result = new byte[getSerializedSize()];
final CodedOutputStream output = CodedOutputStream.newInstance(result);
writeTo(output);
output.checkNoSpaceLeft();
return result;
} catch (IOException e) {
} catch (final IOException e) {
throw new RuntimeException(
"Serializing to a byte array threw an IOException " +
"(should never happen).", e);
@ -174,8 +180,15 @@ public final class UnknownFieldSet {
* Serializes the message and writes it to {@code output}. This is just a
* trivial wrapper around {@link #writeTo(CodedOutputStream)}.
*/
public final void writeTo(OutputStream output) throws IOException {
CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
public void writeTo(final OutputStream output) throws IOException {
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
writeTo(codedOutput);
codedOutput.flush();
}
public void writeDelimitedTo(OutputStream output) throws IOException {
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
codedOutput.writeRawVarint32(getSerializedSize());
writeTo(codedOutput);
codedOutput.flush();
}
@ -183,7 +196,7 @@ public final class UnknownFieldSet {
/** Get the number of bytes required to encode this set. */
public int getSerializedSize() {
int result = 0;
for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
result += entry.getValue().getSerializedSize(entry.getKey());
}
return result;
@ -193,9 +206,9 @@ public final class UnknownFieldSet {
* Serializes the set and writes it to {@code output} using
* {@code MessageSet} wire format.
*/
public void writeAsMessageSetTo(CodedOutputStream output)
public void writeAsMessageSetTo(final CodedOutputStream output)
throws IOException {
for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
entry.getValue().writeAsMessageSetExtensionTo(
entry.getKey(), output);
}
@ -207,37 +220,51 @@ public final class UnknownFieldSet {
*/
public int getSerializedSizeAsMessageSet() {
int result = 0;
for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
result += entry.getValue().getSerializedSizeAsMessageSetExtension(
entry.getKey());
}
return result;
}
public boolean isInitialized() {
// UnknownFieldSets do not have required fields, so they are always
// initialized.
return true;
}
/** Parse an {@code UnknownFieldSet} from the given input stream. */
static public UnknownFieldSet parseFrom(CodedInputStream input)
public static UnknownFieldSet parseFrom(final CodedInputStream input)
throws IOException {
return newBuilder().mergeFrom(input).build();
}
/** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
public static UnknownFieldSet parseFrom(ByteString data)
public static UnknownFieldSet parseFrom(final ByteString data)
throws InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).build();
}
/** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
public static UnknownFieldSet parseFrom(byte[] data)
public static UnknownFieldSet parseFrom(final byte[] data)
throws InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).build();
}
/** Parse an {@code UnknownFieldSet} from {@code input} and return it. */
public static UnknownFieldSet parseFrom(InputStream input)
public static UnknownFieldSet parseFrom(final InputStream input)
throws IOException {
return newBuilder().mergeFrom(input).build();
}
public Builder newBuilderForType() {
return newBuilder();
}
public Builder toBuilder() {
return newBuilder().mergeFrom(this);
}
/**
* Builder for {@link UnknownFieldSet}s.
*
@ -250,21 +277,35 @@ public final class UnknownFieldSet {
*
* <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}.
*/
public static final class Builder {
public static final class Builder implements MessageLite.Builder {
private static ThreadLocalQuickQueue<Builder> builders =
new ThreadLocalQuickQueue<Builder>();
// This constructor should never be called directly (except from 'create').
private Builder() {}
private Map<Integer, Field> fields = new TreeMap<Integer, Field>();
private Map<Integer, Field> fields;
// Optimization: We keep around a builder for the last field that was
// modified so that we can efficiently add to it multiple times in a
// row (important when parsing an unknown repeated field).
int lastFieldNumber = 0;
Field.Builder lastField = null;
private int lastFieldNumber;
private Field.Builder lastField;
private static Builder create() {
Builder builder = builders.get().poll();
if (builder == null) {
builder = new Builder();
}
builder.reinitialize();
return builder;
}
/**
* Get a field builder for the given field number which includes any
* values that already exist.
*/
private Field.Builder getFieldBuilder(int number) {
private Field.Builder getFieldBuilder(final int number) {
if (lastField != null) {
if (number == lastFieldNumber) {
return lastField;
@ -275,7 +316,7 @@ public final class UnknownFieldSet {
if (number == 0) {
return null;
} else {
Field existing = fields.get(number);
final Field existing = fields.get(number);
lastFieldNumber = number;
lastField = Field.newBuilder();
if (existing != null) {
@ -289,26 +330,48 @@ public final class UnknownFieldSet {
* Build the {@link UnknownFieldSet} and return it.
*
* <p>Once {@code build()} has been called, the {@code Builder} will no
* longer be usable. Calling any method after {@code build()} will throw
* {@code NullPointerException}.
* longer be usable. Calling any method after {@code build()} will result
* in undefined behavior and can cause a {@code NullPointerException} to be
* thrown.
*/
public UnknownFieldSet build() {
getFieldBuilder(0); // Force lastField to be built.
UnknownFieldSet result;
final UnknownFieldSet result;
if (fields.isEmpty()) {
result = getDefaultInstance();
} else {
result = new UnknownFieldSet(Collections.unmodifiableMap(fields));
}
fields = null;
builders.get().offer(this);
return result;
}
public UnknownFieldSet buildPartial() {
// No required fields, so this is the same as build().
return build();
}
@Override
public Builder clone() {
getFieldBuilder(0); // Force lastField to be built.
return UnknownFieldSet.newBuilder().mergeFrom(
new UnknownFieldSet(fields));
}
public UnknownFieldSet getDefaultInstanceForType() {
return UnknownFieldSet.getDefaultInstance();
}
private void reinitialize() {
fields = Collections.emptyMap();
lastFieldNumber = 0;
lastField = null;
}
/** Reset the builder to an empty set. */
public Builder clear() {
fields = new TreeMap<Integer, Field>();
lastFieldNumber = 0;
lastField = null;
reinitialize();
return this;
}
@ -317,9 +380,9 @@ public final class UnknownFieldSet {
* exists in both sets, {@code other}'s values for that field will be
* appended to the values in this set.
*/
public Builder mergeFrom(UnknownFieldSet other) {
public Builder mergeFrom(final UnknownFieldSet other) {
if (other != getDefaultInstance()) {
for (Map.Entry<Integer, Field> entry : other.fields.entrySet()) {
for (final Map.Entry<Integer, Field> entry : other.fields.entrySet()) {
mergeField(entry.getKey(), entry.getValue());
}
}
@ -330,7 +393,7 @@ public final class UnknownFieldSet {
* Add a field to the {@code UnknownFieldSet}. If a field with the same
* number already exists, the two are merged.
*/
public Builder mergeField(int number, Field field) {
public Builder mergeField(final int number, final Field field) {
if (number == 0) {
throw new IllegalArgumentException("Zero is not a valid field number.");
}
@ -350,7 +413,7 @@ public final class UnknownFieldSet {
* value. This is used in particular when an unknown enum value is
* encountered.
*/
public Builder mergeVarintField(int number, int value) {
public Builder mergeVarintField(final int number, final int value) {
if (number == 0) {
throw new IllegalArgumentException("Zero is not a valid field number.");
}
@ -359,7 +422,7 @@ public final class UnknownFieldSet {
}
/** Check if the given field number is present in the set. */
public boolean hasField(int number) {
public boolean hasField(final int number) {
if (number == 0) {
throw new IllegalArgumentException("Zero is not a valid field number.");
}
@ -370,7 +433,7 @@ public final class UnknownFieldSet {
* Add a field to the {@code UnknownFieldSet}. If a field with the same
* number already exists, it is removed.
*/
public Builder addField(int number, Field field) {
public Builder addField(final int number, final Field field) {
if (number == 0) {
throw new IllegalArgumentException("Zero is not a valid field number.");
}
@ -379,6 +442,9 @@ public final class UnknownFieldSet {
lastField = null;
lastFieldNumber = 0;
}
if (fields.isEmpty()) {
fields = new TreeMap<Integer,Field>();
}
fields.put(number, field);
return this;
}
@ -396,9 +462,9 @@ public final class UnknownFieldSet {
* Parse an entire message from {@code input} and merge its fields into
* this set.
*/
public Builder mergeFrom(CodedInputStream input) throws IOException {
public Builder mergeFrom(final CodedInputStream input) throws IOException {
while (true) {
int tag = input.readTag();
final int tag = input.readTag();
if (tag == 0 || !mergeFieldFrom(tag, input)) {
break;
}
@ -411,9 +477,9 @@ public final class UnknownFieldSet {
* @param tag The field's tag number, which was already parsed.
* @return {@code false} if the tag is an engroup tag.
*/
public boolean mergeFieldFrom(int tag, CodedInputStream input)
public boolean mergeFieldFrom(final int tag, final CodedInputStream input)
throws IOException {
int number = WireFormat.getTagFieldNumber(tag);
final int number = WireFormat.getTagFieldNumber(tag);
switch (WireFormat.getTagWireType(tag)) {
case WireFormat.WIRETYPE_VARINT:
getFieldBuilder(number).addVarint(input.readInt64());
@ -424,12 +490,12 @@ public final class UnknownFieldSet {
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
getFieldBuilder(number).addLengthDelimited(input.readBytes());
return true;
case WireFormat.WIRETYPE_START_GROUP: {
UnknownFieldSet.Builder subBuilder = UnknownFieldSet.newBuilder();
input.readUnknownGroup(number, subBuilder);
case WireFormat.WIRETYPE_START_GROUP:
final Builder subBuilder = newBuilder();
input.readGroup(number, subBuilder,
ExtensionRegistry.getEmptyRegistry());
getFieldBuilder(number).addGroup(subBuilder.build());
return true;
}
case WireFormat.WIRETYPE_END_GROUP:
return false;
case WireFormat.WIRETYPE_FIXED32:
@ -445,16 +511,16 @@ public final class UnknownFieldSet {
* set being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
public Builder mergeFrom(ByteString data)
public Builder mergeFrom(final ByteString data)
throws InvalidProtocolBufferException {
try {
CodedInputStream input = data.newCodedInput();
final CodedInputStream input = data.newCodedInput();
mergeFrom(input);
input.checkLastTagWas(0);
return this;
} catch (InvalidProtocolBufferException e) {
} catch (final InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
} catch (final IOException e) {
throw new RuntimeException(
"Reading from a ByteString threw an IOException (should " +
"never happen).", e);
@ -466,10 +532,69 @@ public final class UnknownFieldSet {
* set being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
public Builder mergeFrom(byte[] data)
public Builder mergeFrom(final byte[] data)
throws InvalidProtocolBufferException {
try {
CodedInputStream input = CodedInputStream.newInstance(data);
final CodedInputStream input = CodedInputStream.newInstance(data);
mergeFrom(input);
input.checkLastTagWas(0);
return this;
} catch (final InvalidProtocolBufferException e) {
throw e;
} catch (final IOException e) {
throw new RuntimeException(
"Reading from a byte array threw an IOException (should " +
"never happen).", e);
}
}
/**
* Parse an {@code UnknownFieldSet} from {@code input} and merge it with the
* set being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
public Builder mergeFrom(final InputStream input) throws IOException {
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
mergeFrom(codedInput);
codedInput.checkLastTagWas(0);
return this;
}
public Builder mergeDelimitedFrom(InputStream input)
throws IOException {
final int size = CodedInputStream.readRawVarint32(input);
final InputStream limitedInput =
new AbstractMessage.Builder.LimitedInputStream(input, size);
return mergeFrom(limitedInput, null);
}
public Builder mergeDelimitedFrom(
InputStream input,
ExtensionRegistryLite extensionRegistry) throws IOException {
// UnknownFieldSet has no extensions.
return mergeFrom(input);
}
public Builder mergeFrom(
CodedInputStream input,
ExtensionRegistryLite extensionRegistry) throws IOException {
// UnknownFieldSet has no extensions.
return mergeFrom(input);
}
public Builder mergeFrom(
ByteString data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
// UnknownFieldSet has no extensions.
return mergeFrom(data);
}
public Builder mergeFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input =
CodedInputStream.newInstance(data, off, len);
mergeFrom(input);
input.checkLastTagWas(0);
return this;
@ -482,16 +607,33 @@ public final class UnknownFieldSet {
}
}
/**
* Parse an {@code UnknownFieldSet} from {@code input} and merge it with the
* set being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
public Builder mergeFrom(InputStream input) throws IOException {
CodedInputStream codedInput = CodedInputStream.newInstance(input);
mergeFrom(codedInput);
codedInput.checkLastTagWas(0);
return this;
public Builder mergeFrom(
byte[] data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
// UnknownFieldSet has no extensions.
return mergeFrom(data);
}
public Builder mergeFrom(
byte[] data, int off, int len,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
// UnknownFieldSet has no extensions.
return mergeFrom(data, off, len);
}
public Builder mergeFrom(
InputStream input,
ExtensionRegistryLite extensionRegistry) throws IOException {
// UnknownFieldSet has no extensions.
return mergeFrom(input);
}
public boolean isInitialized() {
// UnknownFieldSets do not have required fields, so they are always
// initialized.
return true;
}
}
@ -510,7 +652,7 @@ public final class UnknownFieldSet {
* wire types.
*
* <p>{@code Field} is an immutable class. To construct one, you must use a
* {@link Field.Builder}.
* {@link Builder}.
*
* @see UnknownFieldSet
*/
@ -519,22 +661,22 @@ public final class UnknownFieldSet {
/** Construct a new {@link Builder}. */
public static Builder newBuilder() {
return new Builder();
return Builder.create();
}
/**
* Construct a new {@link Builder} and initialize it to a copy of
* {@code copyFrom}.
*/
public static Builder newBuilder(Field copyFrom) {
return new Builder().mergeFrom(copyFrom);
public static Builder newBuilder(final Field copyFrom) {
return newBuilder().mergeFrom(copyFrom);
}
/** Get an empty {@code Field}. */
public static Field getDefaultInstance() {
return defaultInstance;
return fieldDefaultInstance;
}
private static Field defaultInstance = newBuilder().build();
private static final Field fieldDefaultInstance = newBuilder().build();
/** Get the list of varint values for this field. */
public List<Long> getVarintList() { return varint; }
@ -556,14 +698,14 @@ public final class UnknownFieldSet {
public List<UnknownFieldSet> getGroupList() { return group; }
@Override
public boolean equals(Object other) {
public boolean equals(final Object other) {
if (this == other) {
return true;
}
if (!(other instanceof Field)) {
return false;
}
return Arrays.equals(this.getIdentityArray(),
return Arrays.equals(getIdentityArray(),
((Field) other).getIdentityArray());
}
@ -574,37 +716,37 @@ public final class UnknownFieldSet {
/**
* Returns the array of objects to be used to uniquely identify this
* {@link UnknownFieldSet.Field} instance.
* {@link Field} instance.
*/
private Object[] getIdentityArray() {
return new Object[] {
this.varint,
this.fixed32,
this.fixed64,
this.lengthDelimited,
this.group};
varint,
fixed32,
fixed64,
lengthDelimited,
group};
}
/**
* Serializes the field, including field number, and writes it to
* {@code output}.
*/
public void writeTo(int fieldNumber, CodedOutputStream output)
public void writeTo(final int fieldNumber, final CodedOutputStream output)
throws IOException {
for (long value : varint) {
for (final long value : varint) {
output.writeUInt64(fieldNumber, value);
}
for (int value : fixed32) {
for (final int value : fixed32) {
output.writeFixed32(fieldNumber, value);
}
for (long value : fixed64) {
for (final long value : fixed64) {
output.writeFixed64(fieldNumber, value);
}
for (ByteString value : lengthDelimited) {
for (final ByteString value : lengthDelimited) {
output.writeBytes(fieldNumber, value);
}
for (UnknownFieldSet value : group) {
output.writeUnknownGroup(fieldNumber, value);
for (final UnknownFieldSet value : group) {
output.writeGroup(fieldNumber, value);
}
}
@ -612,22 +754,22 @@ public final class UnknownFieldSet {
* Get the number of bytes required to encode this field, including field
* number.
*/
public int getSerializedSize(int fieldNumber) {
public int getSerializedSize(final int fieldNumber) {
int result = 0;
for (long value : varint) {
for (final long value : varint) {
result += CodedOutputStream.computeUInt64Size(fieldNumber, value);
}
for (int value : fixed32) {
for (final int value : fixed32) {
result += CodedOutputStream.computeFixed32Size(fieldNumber, value);
}
for (long value : fixed64) {
for (final long value : fixed64) {
result += CodedOutputStream.computeFixed64Size(fieldNumber, value);
}
for (ByteString value : lengthDelimited) {
for (final ByteString value : lengthDelimited) {
result += CodedOutputStream.computeBytesSize(fieldNumber, value);
}
for (UnknownFieldSet value : group) {
result += CodedOutputStream.computeUnknownGroupSize(fieldNumber, value);
for (final UnknownFieldSet value : group) {
result += CodedOutputStream.computeGroupSize(fieldNumber, value);
}
return result;
}
@ -637,10 +779,10 @@ public final class UnknownFieldSet {
* {@code output}, using {@code MessageSet} wire format.
*/
public void writeAsMessageSetExtensionTo(
int fieldNumber,
CodedOutputStream output)
final int fieldNumber,
final CodedOutputStream output)
throws IOException {
for (ByteString value : lengthDelimited) {
for (final ByteString value : lengthDelimited) {
output.writeRawMessageSetExtension(fieldNumber, value);
}
}
@ -649,9 +791,9 @@ public final class UnknownFieldSet {
* Get the number of bytes required to encode this field, including field
* number, using {@code MessageSet} wire format.
*/
public int getSerializedSizeAsMessageSetExtension(int fieldNumber) {
public int getSerializedSizeAsMessageSetExtension(final int fieldNumber) {
int result = 0;
for (ByteString value : lengthDelimited) {
for (final ByteString value : lengthDelimited) {
result += CodedOutputStream.computeRawMessageSetExtensionSize(
fieldNumber, value);
}
@ -670,13 +812,29 @@ public final class UnknownFieldSet {
* <p>Use {@link Field#newBuilder()} to construct a {@code Builder}.
*/
public static final class Builder {
private static ThreadLocalQuickQueue<Builder> builders =
new ThreadLocalQuickQueue<Builder>();
// This constructor should never be called directly (except from 'create').
private Builder() {}
private Field result = new Field();
private static Builder create() {
Builder builder = builders.get().poll();
if (builder == null) {
builder = new Builder();
}
builder.result = new Field();
return builder;
}
private Field result;
/**
* Build the field. After {@code build()} has been called, the
* {@code Builder} is no longer usable. Calling any other method will
* throw a {@code NullPointerException}.
* result in undefined behavior and can cause a
* {@code NullPointerException} to be thrown.
*/
public Field build() {
if (result.varint == null) {
@ -706,8 +864,9 @@ public final class UnknownFieldSet {
result.group = Collections.unmodifiableList(result.group);
}
Field returnMe = result;
final Field returnMe = result;
result = null;
builders.get().offer(this);
return returnMe;
}
@ -722,7 +881,7 @@ public final class UnknownFieldSet {
* of values, {@code other}'s values are append to the ones in this
* field.
*/
public Builder mergeFrom(Field other) {
public Builder mergeFrom(final Field other) {
if (!other.varint.isEmpty()) {
if (result.varint == null) {
result.varint = new ArrayList<Long>();
@ -757,7 +916,7 @@ public final class UnknownFieldSet {
}
/** Add a varint value. */
public Builder addVarint(long value) {
public Builder addVarint(final long value) {
if (result.varint == null) {
result.varint = new ArrayList<Long>();
}
@ -766,7 +925,7 @@ public final class UnknownFieldSet {
}
/** Add a fixed32 value. */
public Builder addFixed32(int value) {
public Builder addFixed32(final int value) {
if (result.fixed32 == null) {
result.fixed32 = new ArrayList<Integer>();
}
@ -775,7 +934,7 @@ public final class UnknownFieldSet {
}
/** Add a fixed64 value. */
public Builder addFixed64(long value) {
public Builder addFixed64(final long value) {
if (result.fixed64 == null) {
result.fixed64 = new ArrayList<Long>();
}
@ -784,7 +943,7 @@ public final class UnknownFieldSet {
}
/** Add a length-delimited value. */
public Builder addLengthDelimited(ByteString value) {
public Builder addLengthDelimited(final ByteString value) {
if (result.lengthDelimited == null) {
result.lengthDelimited = new ArrayList<ByteString>();
}
@ -793,7 +952,7 @@ public final class UnknownFieldSet {
}
/** Add an embedded group. */
public Builder addGroup(UnknownFieldSet value) {
public Builder addGroup(final UnknownFieldSet value) {
if (result.group == null) {
result.group = new ArrayList<UnknownFieldSet>();
}

View File

@ -56,54 +56,84 @@ public final class WireFormat {
static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1;
/** Given a tag value, determines the wire type (the lower 3 bits). */
static int getTagWireType(int tag) {
static int getTagWireType(final int tag) {
return tag & TAG_TYPE_MASK;
}
/** Given a tag value, determines the field number (the upper 29 bits). */
public static int getTagFieldNumber(int tag) {
public static int getTagFieldNumber(final int tag) {
return tag >>> TAG_TYPE_BITS;
}
/** Makes a tag value given a field number and wire type. */
static int makeTag(int fieldNumber, int wireType) {
static int makeTag(final int fieldNumber, final int wireType) {
return (fieldNumber << TAG_TYPE_BITS) | wireType;
}
static int getWireFormatForFieldType(Descriptors.FieldDescriptor.Type type) {
switch (type) {
case DOUBLE : return WIRETYPE_FIXED64;
case FLOAT : return WIRETYPE_FIXED32;
case INT64 : return WIRETYPE_VARINT;
case UINT64 : return WIRETYPE_VARINT;
case INT32 : return WIRETYPE_VARINT;
case FIXED64 : return WIRETYPE_FIXED64;
case FIXED32 : return WIRETYPE_FIXED32;
case BOOL : return WIRETYPE_VARINT;
case STRING : return WIRETYPE_LENGTH_DELIMITED;
case GROUP : return WIRETYPE_START_GROUP;
case MESSAGE : return WIRETYPE_LENGTH_DELIMITED;
case BYTES : return WIRETYPE_LENGTH_DELIMITED;
case UINT32 : return WIRETYPE_VARINT;
case ENUM : return WIRETYPE_VARINT;
case SFIXED32: return WIRETYPE_FIXED32;
case SFIXED64: return WIRETYPE_FIXED64;
case SINT32 : return WIRETYPE_VARINT;
case SINT64 : return WIRETYPE_VARINT;
/**
* Lite equivalent to {@link Descriptors.FieldDescriptor.JavaType}. This is
* only here to support the lite runtime and should not be used by users.
*/
public enum JavaType {
INT(0),
LONG(0L),
FLOAT(0F),
DOUBLE(0D),
BOOLEAN(false),
STRING(""),
BYTE_STRING(ByteString.EMPTY),
ENUM(null),
MESSAGE(null);
JavaType(final Object defaultDefault) {
this.defaultDefault = defaultDefault;
}
throw new RuntimeException(
"There is no way to get here, but the compiler thinks otherwise.");
/**
* The default default value for fields of this type, if it's a primitive
* type.
*/
Object getDefaultDefault() {
return defaultDefault;
}
private final Object defaultDefault;
}
/** Given a field descriptor, returns the wire type. This differs from
* getWireFormatForFieldType for packed repeated fields. */
static int getWireFormatForField(Descriptors.FieldDescriptor descriptor) {
if (descriptor.getOptions().getPacked()) {
return WIRETYPE_LENGTH_DELIMITED;
} else {
return getWireFormatForFieldType(descriptor.getType());
/**
* Lite equivalent to {@link Descriptors.FieldDescriptor.Type}. This is
* only here to support the lite runtime and should not be used by users.
*/
public enum FieldType {
DOUBLE (JavaType.DOUBLE , WIRETYPE_FIXED64 ),
FLOAT (JavaType.FLOAT , WIRETYPE_FIXED32 ),
INT64 (JavaType.LONG , WIRETYPE_VARINT ),
UINT64 (JavaType.LONG , WIRETYPE_VARINT ),
INT32 (JavaType.INT , WIRETYPE_VARINT ),
FIXED64 (JavaType.LONG , WIRETYPE_FIXED64 ),
FIXED32 (JavaType.INT , WIRETYPE_FIXED32 ),
BOOL (JavaType.BOOLEAN , WIRETYPE_VARINT ),
STRING (JavaType.STRING , WIRETYPE_LENGTH_DELIMITED),
GROUP (JavaType.MESSAGE , WIRETYPE_START_GROUP ),
MESSAGE (JavaType.MESSAGE , WIRETYPE_LENGTH_DELIMITED),
BYTES (JavaType.BYTE_STRING, WIRETYPE_LENGTH_DELIMITED),
UINT32 (JavaType.INT , WIRETYPE_VARINT ),
ENUM (JavaType.ENUM , WIRETYPE_VARINT ),
SFIXED32(JavaType.INT , WIRETYPE_FIXED32 ),
SFIXED64(JavaType.LONG , WIRETYPE_FIXED64 ),
SINT32 (JavaType.INT , WIRETYPE_VARINT ),
SINT64 (JavaType.LONG , WIRETYPE_VARINT );
FieldType(final JavaType javaType, final int wireType) {
this.javaType = javaType;
this.wireType = wireType;
}
private final JavaType javaType;
private final int wireType;
public JavaType getJavaType() { return javaType; }
public int getWireType() { return wireType; }
}
// Field numbers for feilds in MessageSet wire format.

View File

@ -367,4 +367,34 @@ public class DescriptorsTest extends TestCase {
assertEquals(UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2,
method.getOptions().getExtension(UnittestCustomOptions.methodOpt1));
}
/**
* Test that the FieldDescriptor.Type enum is the same as the
* WireFormat.FieldType enum.
*/
public void testFieldTypeTablesMatch() throws Exception {
FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values();
WireFormat.FieldType[] values2 = WireFormat.FieldType.values();
assertEquals(values1.length, values2.length);
for (int i = 0; i < values1.length; i++) {
assertEquals(values1[i].toString(), values2[i].toString());
}
}
/**
* Test that the FieldDescriptor.JavaType enum is the same as the
* WireFormat.JavaType enum.
*/
public void testJavaTypeTablesMatch() throws Exception {
FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values();
WireFormat.JavaType[] values2 = WireFormat.JavaType.values();
assertEquals(values1.length, values2.length);
for (int i = 0; i < values1.length; i++) {
assertEquals(values1[i].toString(), values2[i].toString());
}
}
}

View File

@ -73,6 +73,18 @@ public class DynamicMessageTest extends TestCase {
}
}
public void testClearAfterBuildError() throws Exception {
Message.Builder builder =
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
builder.build();
try {
builder.clear();
fail("Should have thrown exception.");
} catch (IllegalStateException e) {
// Success.
}
}
public void testDynamicMessageSettersRejectNull() throws Exception {
Message.Builder builder =
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());

View File

@ -43,6 +43,8 @@ import protobuf_unittest.MultipleFilesTestProto;
import protobuf_unittest.MessageWithNoOuter;
import protobuf_unittest.EnumWithNoOuter;
import protobuf_unittest.ServiceWithNoOuter;
import com.google.protobuf.UnittestLite;
import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
import junit.framework.TestCase;
import java.util.Arrays;
@ -82,6 +84,17 @@ public class GeneratedMessageTest extends TestCase {
}
}
public void testClearAfterBuildError() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
builder.build();
try {
builder.clear();
fail("Should have thrown exception.");
} catch (IllegalStateException e) {
// Success.
}
}
public void testSettersRejectNull() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
try {
@ -338,6 +351,16 @@ public class GeneratedMessageTest extends TestCase {
instanceof ProtocolMessageEnum);
}
public void testEnumMap() throws Exception {
Internal.EnumLiteMap<ForeignEnum> map = ForeignEnum.internalGetValueMap();
for (ForeignEnum value : ForeignEnum.values()) {
assertEquals(value, map.findValueByNumber(value.getNumber()));
}
assertTrue(map.findValueByNumber(12345) == null);
}
// =================================================================
// Extensions.
@ -420,6 +443,12 @@ public class GeneratedMessageTest extends TestCase {
.getExtensionCount(UnittestProto.repeatedInt32Extension));
}
public void testExtensionCopy() throws Exception {
TestAllExtensions original = TestUtil.getAllExtensionsSet();
TestAllExtensions copy = TestAllExtensions.newBuilder(original).build();
TestUtil.assertAllExtensionsSet(copy);
}
public void testExtensionMergeFrom() throws Exception {
TestAllExtensions original =
TestAllExtensions.newBuilder()
@ -431,6 +460,66 @@ public class GeneratedMessageTest extends TestCase {
1, (int) merged.getExtension(UnittestProto.optionalInt32Extension));
}
// =================================================================
// Lite Extensions.
// We test lite extensions directly because they have a separate
// implementation from full extensions. In contrast, we do not test
// lite fields directly since they are implemented exactly the same as
// regular fields.
public void testLiteExtensionAccessors() throws Exception {
TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
TestUtil.setAllExtensions(builder);
TestAllExtensionsLite message = builder.build();
TestUtil.assertAllExtensionsSet(message);
}
public void testLiteExtensionRepeatedSetters() throws Exception {
TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
TestUtil.setAllExtensions(builder);
TestUtil.modifyRepeatedExtensions(builder);
TestAllExtensionsLite message = builder.build();
TestUtil.assertRepeatedExtensionsModified(message);
}
public void testLiteExtensionDefaults() throws Exception {
TestUtil.assertExtensionsClear(TestAllExtensionsLite.getDefaultInstance());
TestUtil.assertExtensionsClear(TestAllExtensionsLite.newBuilder().build());
}
public void testClearLiteExtension() throws Exception {
// clearExtension() is not actually used in TestUtil, so try it manually.
assertFalse(
TestAllExtensionsLite.newBuilder()
.setExtension(UnittestLite.optionalInt32ExtensionLite, 1)
.clearExtension(UnittestLite.optionalInt32ExtensionLite)
.hasExtension(UnittestLite.optionalInt32ExtensionLite));
assertEquals(0,
TestAllExtensionsLite.newBuilder()
.addExtension(UnittestLite.repeatedInt32ExtensionLite, 1)
.clearExtension(UnittestLite.repeatedInt32ExtensionLite)
.getExtensionCount(UnittestLite.repeatedInt32ExtensionLite));
}
public void testLiteExtensionCopy() throws Exception {
TestAllExtensionsLite original = TestUtil.getAllLiteExtensionsSet();
TestAllExtensionsLite copy =
TestAllExtensionsLite.newBuilder(original).build();
TestUtil.assertAllExtensionsSet(copy);
}
public void testLiteExtensionMergeFrom() throws Exception {
TestAllExtensionsLite original =
TestAllExtensionsLite.newBuilder()
.setExtension(UnittestLite.optionalInt32ExtensionLite, 1).build();
TestAllExtensionsLite merged =
TestAllExtensionsLite.newBuilder().mergeFrom(original).build();
assertTrue(merged.hasExtension(UnittestLite.optionalInt32ExtensionLite));
assertEquals(
1, (int) merged.getExtension(UnittestLite.optionalInt32ExtensionLite));
}
// =================================================================
// multiple_files_test

View File

@ -0,0 +1,114 @@
// 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 com.google.protobuf.UnittestLite;
import com.google.protobuf.UnittestLite.TestAllTypesLite;
import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
import com.google.protobuf.UnittestLite.TestNestedExtensionLite;
import junit.framework.TestCase;
/**
* Test lite runtime.
*
* @author kenton@google.com Kenton Varda
*/
public class LiteTest extends TestCase {
public void setUp() throws Exception {
// Test that nested extensions are initialized correctly even if the outer
// class has not been accessed directly. This was once a bug with lite
// messages.
//
// We put this in setUp() rather than in its own test method because we
// need to make sure it runs before any actual tests.
assertTrue(TestNestedExtensionLite.nestedExtension != null);
}
public void testLite() throws Exception {
// Since lite messages are a subset of regular messages, we can mostly
// assume that the functionality of lite messages is already thoroughly
// tested by the regular tests. All this test really verifies is that
// a proto with optimize_for = LITE_RUNTIME compiles correctly when
// linked only against the lite library. That is all tested at compile
// time, leaving not much to do in this method. Let's just do some random
// stuff to make sure the lite message is actually here and usable.
TestAllTypesLite message =
TestAllTypesLite.newBuilder()
.setOptionalInt32(123)
.addRepeatedString("hello")
.setOptionalNestedMessage(
TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
.build();
ByteString data = message.toByteString();
TestAllTypesLite message2 = TestAllTypesLite.parseFrom(data);
assertEquals(123, message2.getOptionalInt32());
assertEquals(1, message2.getRepeatedStringCount());
assertEquals("hello", message2.getRepeatedString(0));
assertEquals(7, message2.getOptionalNestedMessage().getBb());
}
public void testLiteExtensions() throws Exception {
// TODO(kenton): Unlike other features of the lite library, extensions are
// implemented completely differently from the regular library. We
// need to test them more thoroughly, once they are fully-implemented.
TestAllExtensionsLite message =
TestAllExtensionsLite.newBuilder()
.setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
.addExtension(UnittestLite.repeatedStringExtensionLite, "hello")
.setExtension(UnittestLite.optionalNestedEnumExtensionLite,
TestAllTypesLite.NestedEnum.BAZ)
.setExtension(UnittestLite.optionalNestedMessageExtensionLite,
TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
.build();
// Test copying a message, since coping extensions actually does use a
// different code path between lite and regular libraries, and as of this
// writing, parsing hasn't been implemented yet.
TestAllExtensionsLite message2 = message.toBuilder().build();
assertEquals(123, (int) message2.getExtension(
UnittestLite.optionalInt32ExtensionLite));
assertEquals(1, message2.getExtensionCount(
UnittestLite.repeatedStringExtensionLite));
assertEquals("hello", message2.getExtension(
UnittestLite.repeatedStringExtensionLite, 0));
assertEquals(TestAllTypesLite.NestedEnum.BAZ, message2.getExtension(
UnittestLite.optionalNestedEnumExtensionLite));
assertEquals(7, message2.getExtension(
UnittestLite.optionalNestedMessageExtensionLite).getBb());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -30,9 +30,12 @@
package com.google.protobuf;
import com.google.protobuf.Descriptors.FieldDescriptor;
import protobuf_unittest.UnittestProto.OneString;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestEmptyMessage;
import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
import protobuf_unittest.UnittestMset.TestMessageSet;
import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
@ -173,6 +176,22 @@ public class TextFormatTest extends TestCase {
TextFormat.printToString(message));
}
public void testPrintField() throws Exception {
final FieldDescriptor dataField =
OneString.getDescriptor().findFieldByName("data");
assertEquals(
"data: \"test data\"\n",
TextFormat.printFieldToString(dataField, "test data"));
final FieldDescriptor optionalField =
TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
final Object value = NestedMessage.newBuilder().setBb(42).build();
assertEquals(
"optional_nested_message {\n bb: 42\n}\n",
TextFormat.printFieldToString(optionalField, value));
}
/**
* Helper to construct a ByteString from a String containing only 8-bit
* characters. The characters are converted directly to bytes, *not*
@ -450,21 +469,21 @@ public class TextFormatTest extends TestCase {
try {
TextFormat.unescapeText("\\x");
fail("Should have thrown an exception.");
} catch (TextFormat.InvalidEscapeSequence e) {
} catch (TextFormat.InvalidEscapeSequenceException e) {
// success
}
try {
TextFormat.unescapeText("\\z");
fail("Should have thrown an exception.");
} catch (TextFormat.InvalidEscapeSequence e) {
} catch (TextFormat.InvalidEscapeSequenceException e) {
// success
}
try {
TextFormat.unescapeText("\\");
fail("Should have thrown an exception.");
} catch (TextFormat.InvalidEscapeSequence e) {
} catch (TextFormat.InvalidEscapeSequenceException e) {
// success
}
}

View File

@ -45,6 +45,8 @@ import protobuf_unittest.UnittestMset.TestMessageSet;
import protobuf_unittest.UnittestMset.RawMessageSet;
import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
/**
* Tests related to parsing and serialization.
@ -100,6 +102,32 @@ public class WireFormatTest extends TestCase {
assertEquals(rawBytes, rawBytes2);
}
public void testSerializeExtensionsLite() throws Exception {
// TestAllTypes and TestAllExtensions should have compatible wire formats,
// so if we serialize a TestAllExtensions then parse it as TestAllTypes
// it should work.
TestAllExtensionsLite message = TestUtil.getAllLiteExtensionsSet();
ByteString rawBytes = message.toByteString();
assertEquals(rawBytes.size(), message.getSerializedSize());
TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
TestUtil.assertAllFieldsSet(message2);
}
public void testSerializePackedExtensionsLite() throws Exception {
// TestPackedTypes and TestPackedExtensions should have compatible wire
// formats; check that they serialize to the same string.
TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet();
ByteString rawBytes = message.toByteString();
TestPackedTypes message2 = TestUtil.getPackedSet();
ByteString rawBytes2 = message2.toByteString();
assertEquals(rawBytes, rawBytes2);
}
public void testParseExtensions() throws Exception {
// TestAllTypes and TestAllExtensions should have compatible wire formats,
// so if we serialize a TestAllTypes then parse it as TestAllExtensions
@ -129,6 +157,43 @@ public class WireFormatTest extends TestCase {
TestUtil.assertPackedExtensionsSet(message2);
}
public void testParseExtensionsLite() throws Exception {
// TestAllTypes and TestAllExtensions should have compatible wire formats,
// so if we serialize a TestAllTypes then parse it as TestAllExtensions
// it should work.
TestAllTypes message = TestUtil.getAllSet();
ByteString rawBytes = message.toByteString();
ExtensionRegistryLite registry_lite = TestUtil.getExtensionRegistryLite();
TestAllExtensionsLite message2 =
TestAllExtensionsLite.parseFrom(rawBytes, registry_lite);
TestUtil.assertAllExtensionsSet(message2);
// Try again using a full extension registry.
ExtensionRegistry registry = TestUtil.getExtensionRegistry();
TestAllExtensionsLite message3 =
TestAllExtensionsLite.parseFrom(rawBytes, registry);
TestUtil.assertAllExtensionsSet(message3);
}
public void testParsePackedExtensionsLite() throws Exception {
// Ensure that packed extensions can be properly parsed.
TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet();
ByteString rawBytes = message.toByteString();
ExtensionRegistryLite registry = TestUtil.getExtensionRegistryLite();
TestPackedExtensionsLite message2 =
TestPackedExtensionsLite.parseFrom(rawBytes, registry);
TestUtil.assertPackedExtensionsSet(message2);
}
public void testExtensionsSerializedSize() throws Exception {
assertEquals(TestUtil.getAllSet().getSerializedSize(),
TestUtil.getAllExtensionsSet().getSerializedSize());

View File

@ -112,9 +112,11 @@ class RepeatedScalarFieldContainer(BaseContainer):
return
orig_empty = len(self._values) == 0
new_values = []
for elem in elem_seq:
self._type_checker.CheckValue(elem)
self._values.extend(elem_seq)
new_values.append(elem)
self._values.extend(new_values)
self._message_listener.ByteSizeDirty()
if orig_empty:
self._message_listener.TransitionToNonempty()
@ -139,9 +141,11 @@ class RepeatedScalarFieldContainer(BaseContainer):
def __setslice__(self, start, stop, values):
"""Sets the subset of items from between the specified indices."""
new_values = []
for value in values:
self._type_checker.CheckValue(value)
self._values[start:stop] = list(values)
new_values.append(value)
self._values[start:stop] = new_values
self._message_listener.ByteSizeDirty()
def __delitem__(self, key):

View File

@ -135,12 +135,12 @@ class Decoder(object):
def ReadFloat(self):
"""Reads and returns a 4-byte floating-point number."""
serialized = self._stream.ReadBytes(4)
return struct.unpack('f', serialized)[0]
return struct.unpack(wire_format.FORMAT_FLOAT_LITTLE_ENDIAN, serialized)[0]
def ReadDouble(self):
"""Reads and returns an 8-byte floating-point number."""
serialized = self._stream.ReadBytes(8)
return struct.unpack('d', serialized)[0]
return struct.unpack(wire_format.FORMAT_DOUBLE_LITTLE_ENDIAN, serialized)[0]
def ReadBool(self):
"""Reads and returns a bool."""

View File

@ -36,12 +36,12 @@ __author__ = 'robinson@google.com (Will Robinson)'
import struct
import unittest
from google.protobuf.internal import wire_format
from google.protobuf.internal import encoder
from google.protobuf.internal import decoder
import logging
from google.protobuf.internal import encoder
from google.protobuf.internal import input_stream
from google.protobuf.internal import wire_format
from google.protobuf import message
import logging
import mox
@ -110,6 +110,10 @@ class DecoderTest(unittest.TestCase):
self.mox.VerifyAll()
self.mox.ResetAll()
VAL = 1.125 # Perfectly representable as a float (no rounding error).
LITTLE_FLOAT_VAL = '\x00\x00\x90?'
LITTLE_DOUBLE_VAL = '\x00\x00\x00\x00\x00\x00\xf2?'
def testReadScalars(self):
test_string = 'I can feel myself getting sutpider.'
scalar_tests = [
@ -125,10 +129,10 @@ class DecoderTest(unittest.TestCase):
'ReadLittleEndian32', long(0xffffffff)],
['sfixed64', decoder.Decoder.ReadSFixed64, long(-1),
'ReadLittleEndian64', 0xffffffffffffffff],
['float', decoder.Decoder.ReadFloat, 0.0,
'ReadBytes', struct.pack('f', 0.0), 4],
['double', decoder.Decoder.ReadDouble, 0.0,
'ReadBytes', struct.pack('d', 0.0), 8],
['float', decoder.Decoder.ReadFloat, self.VAL,
'ReadBytes', self.LITTLE_FLOAT_VAL, 4],
['double', decoder.Decoder.ReadDouble, self.VAL,
'ReadBytes', self.LITTLE_DOUBLE_VAL, 8],
['bool', decoder.Decoder.ReadBool, True, 'ReadVarUInt32', 1],
['enum', decoder.Decoder.ReadEnum, 23, 'ReadVarUInt32', 23],
['string', decoder.Decoder.ReadString,

View File

@ -123,11 +123,13 @@ class Encoder(object):
def AppendFloatNoTag(self, value):
"""Appends a floating-point number to our buffer."""
self._stream.AppendRawBytes(struct.pack('f', value))
self._stream.AppendRawBytes(
struct.pack(wire_format.FORMAT_FLOAT_LITTLE_ENDIAN, value))
def AppendDoubleNoTag(self, value):
"""Appends a double-precision floating-point number to our buffer."""
self._stream.AppendRawBytes(struct.pack('d', value))
self._stream.AppendRawBytes(
struct.pack(wire_format.FORMAT_DOUBLE_LITTLE_ENDIAN, value))
def AppendBoolNoTag(self, value):
"""Appends a boolean to our buffer."""

View File

@ -123,6 +123,10 @@ class EncoderTest(unittest.TestCase):
self.mox.VerifyAll()
self.mox.ResetAll()
VAL = 1.125 # Perfectly representable as a float (no rounding error).
LITTLE_FLOAT_VAL = '\x00\x00\x90?'
LITTLE_DOUBLE_VAL = '\x00\x00\x00\x00\x00\x00\xf2?'
def testAppendScalars(self):
utf8_bytes = '\xd0\xa2\xd0\xb5\xd1\x81\xd1\x82'
utf8_string = unicode(utf8_bytes, 'utf-8')
@ -144,9 +148,9 @@ class EncoderTest(unittest.TestCase):
['sfixed64', self.encoder.AppendSFixed64, 'AppendLittleEndian64',
wire_format.WIRETYPE_FIXED64, -1, 0xffffffffffffffff],
['float', self.encoder.AppendFloat, 'AppendRawBytes',
wire_format.WIRETYPE_FIXED32, 0.0, struct.pack('f', 0.0)],
wire_format.WIRETYPE_FIXED32, self.VAL, self.LITTLE_FLOAT_VAL],
['double', self.encoder.AppendDouble, 'AppendRawBytes',
wire_format.WIRETYPE_FIXED64, 0.0, struct.pack('d', 0.0)],
wire_format.WIRETYPE_FIXED64, self.VAL, self.LITTLE_DOUBLE_VAL],
['bool', self.encoder.AppendBool, 'AppendVarint32',
wire_format.WIRETYPE_VARINT, False],
['enum', self.encoder.AppendEnum, 'AppendVarint32',
@ -185,9 +189,9 @@ class EncoderTest(unittest.TestCase):
['sfixed64', self.encoder.AppendSFixed64NoTag,
'AppendLittleEndian64', None, 0],
['float', self.encoder.AppendFloatNoTag,
'AppendRawBytes', None, 0.0, struct.pack('f', 0.0)],
'AppendRawBytes', None, self.VAL, self.LITTLE_FLOAT_VAL],
['double', self.encoder.AppendDoubleNoTag,
'AppendRawBytes', None, 0.0, struct.pack('d', 0.0)],
'AppendRawBytes', None, self.VAL, self.LITTLE_DOUBLE_VAL],
['bool', self.encoder.AppendBoolNoTag, 'AppendVarint32', None, 0],
['enum', self.encoder.AppendEnumNoTag, 'AppendVarint32', None, 0],
['sint32', self.encoder.AppendSInt32NoTag,

View File

@ -0,0 +1,53 @@
#! /usr/bin/python
#
# 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.
"""Tests python protocol buffers against the golden message."""
__author__ = 'gps@google.com (Gregory P. Smith)'
import unittest
from google.protobuf import unittest_import_pb2
from google.protobuf import unittest_pb2
from google.protobuf.internal import test_util
class MessageTest(test_util.GoldenMessageTestCase):
def testGoldenMessage(self):
golden_data = test_util.GoldenFile('golden_message').read()
golden_message = unittest_pb2.TestAllTypes()
golden_message.ParseFromString(golden_data)
self.ExpectAllFieldsSet(golden_message)
if __name__ == '__main__':
unittest.main()

View File

@ -232,13 +232,14 @@ class ReflectionTest(unittest.TestCase):
proto.repeated_string.extend(['foo', 'bar'])
proto.repeated_string.extend([])
proto.repeated_string.append('baz')
proto.repeated_string.extend(str(x) for x in xrange(2))
proto.optional_int32 = 21
self.assertEqual(
[ (proto.DESCRIPTOR.fields_by_name['optional_int32' ], 21),
(proto.DESCRIPTOR.fields_by_name['repeated_int32' ], [5, 11]),
(proto.DESCRIPTOR.fields_by_name['repeated_fixed32'], [1]),
(proto.DESCRIPTOR.fields_by_name['repeated_string' ],
['foo', 'bar', 'baz']) ],
['foo', 'bar', 'baz', '0', '1']) ],
proto.ListFields())
def testSingularListExtensions(self):
@ -447,6 +448,10 @@ class ReflectionTest(unittest.TestCase):
self.assertEqual([25, 20, 15], proto.repeated_int32[1:4])
self.assertEqual([5, 25, 20, 15, 30], proto.repeated_int32[:])
# Test slice assignment with an iterator
proto.repeated_int32[1:4] = (i for i in xrange(3))
self.assertEqual([5, 0, 1, 2, 30], proto.repeated_int32)
# Test slice assignment.
proto.repeated_int32[1:4] = [35, 40, 45]
self.assertEqual([5, 35, 40, 45, 30], proto.repeated_int32)
@ -1739,13 +1744,14 @@ class SerializationTest(unittest.TestCase):
self.assertEqual(2, proto2.b)
self.assertEqual(3, proto2.c)
def testSerializedAllPackedFields(self):
def testSerializeAllPackedFields(self):
first_proto = unittest_pb2.TestPackedTypes()
second_proto = unittest_pb2.TestPackedTypes()
test_util.SetAllPackedFields(first_proto)
serialized = first_proto.SerializeToString()
self.assertEqual(first_proto.ByteSize(), len(serialized))
second_proto.MergeFromString(serialized)
bytes_read = second_proto.MergeFromString(serialized)
self.assertEqual(second_proto.ByteSize(), bytes_read)
self.assertEqual(first_proto, second_proto)
def testSerializeAllPackedExtensions(self):
@ -1753,7 +1759,8 @@ class SerializationTest(unittest.TestCase):
second_proto = unittest_pb2.TestPackedExtensions()
test_util.SetAllPackedExtensions(first_proto)
serialized = first_proto.SerializeToString()
second_proto.MergeFromString(serialized)
bytes_read = second_proto.MergeFromString(serialized)
self.assertEqual(second_proto.ByteSize(), bytes_read)
self.assertEqual(first_proto, second_proto)
def testMergePackedFromStringWhenSomeFieldsAlreadySet(self):
@ -1838,6 +1845,79 @@ class SerializationTest(unittest.TestCase):
self.assertEqual(unittest_pb2.REPEATED_NESTED_ENUM_EXTENSION_FIELD_NUMBER,
51)
def testInitKwargs(self):
proto = unittest_pb2.TestAllTypes(
optional_int32=1,
optional_string='foo',
optional_bool=True,
optional_bytes='bar',
optional_nested_message=unittest_pb2.TestAllTypes.NestedMessage(bb=1),
optional_foreign_message=unittest_pb2.ForeignMessage(c=1),
optional_nested_enum=unittest_pb2.TestAllTypes.FOO,
optional_foreign_enum=unittest_pb2.FOREIGN_FOO,
repeated_int32=[1, 2, 3])
self.assertTrue(proto.IsInitialized())
self.assertTrue(proto.HasField('optional_int32'))
self.assertTrue(proto.HasField('optional_string'))
self.assertTrue(proto.HasField('optional_bool'))
self.assertTrue(proto.HasField('optional_bytes'))
self.assertTrue(proto.HasField('optional_nested_message'))
self.assertTrue(proto.HasField('optional_foreign_message'))
self.assertTrue(proto.HasField('optional_nested_enum'))
self.assertTrue(proto.HasField('optional_foreign_enum'))
self.assertEqual(1, proto.optional_int32)
self.assertEqual('foo', proto.optional_string)
self.assertEqual(True, proto.optional_bool)
self.assertEqual('bar', proto.optional_bytes)
self.assertEqual(1, proto.optional_nested_message.bb)
self.assertEqual(1, proto.optional_foreign_message.c)
self.assertEqual(unittest_pb2.TestAllTypes.FOO,
proto.optional_nested_enum)
self.assertEqual(unittest_pb2.FOREIGN_FOO, proto.optional_foreign_enum)
self.assertEqual([1, 2, 3], proto.repeated_int32)
def testInitArgsUnknownFieldName(self):
def InitalizeEmptyMessageWithExtraKeywordArg():
unused_proto = unittest_pb2.TestEmptyMessage(unknown='unknown')
self._CheckRaises(ValueError,
InitalizeEmptyMessageWithExtraKeywordArg,
'Protocol message has no "unknown" field.')
def testInitRequiredKwargs(self):
proto = unittest_pb2.TestRequired(a=1, b=1, c=1)
self.assertTrue(proto.IsInitialized())
self.assertTrue(proto.HasField('a'))
self.assertTrue(proto.HasField('b'))
self.assertTrue(proto.HasField('c'))
self.assertTrue(not proto.HasField('dummy2'))
self.assertEqual(1, proto.a)
self.assertEqual(1, proto.b)
self.assertEqual(1, proto.c)
def testInitRequiredForeignKwargs(self):
proto = unittest_pb2.TestRequiredForeign(
optional_message=unittest_pb2.TestRequired(a=1, b=1, c=1))
self.assertTrue(proto.IsInitialized())
self.assertTrue(proto.HasField('optional_message'))
self.assertTrue(proto.optional_message.IsInitialized())
self.assertTrue(proto.optional_message.HasField('a'))
self.assertTrue(proto.optional_message.HasField('b'))
self.assertTrue(proto.optional_message.HasField('c'))
self.assertTrue(not proto.optional_message.HasField('dummy2'))
self.assertEqual(unittest_pb2.TestRequired(a=1, b=1, c=1),
proto.optional_message)
self.assertEqual(1, proto.optional_message.a)
self.assertEqual(1, proto.optional_message.b)
self.assertEqual(1, proto.optional_message.c)
def testInitRepeatedKwargs(self):
proto = unittest_pb2.TestAllTypes(repeated_int32=[1, 2, 3])
self.assertTrue(proto.IsInitialized())
self.assertEqual(1, proto.repeated_int32[0])
self.assertEqual(2, proto.repeated_int32[1])
self.assertEqual(3, proto.repeated_int32[2])
class OptionsTest(unittest.TestCase):
def testMessageOptions(self):

View File

@ -38,6 +38,7 @@ __author__ = 'robinson@google.com (Will Robinson)'
import os.path
import unittest
from google.protobuf import unittest_import_pb2
from google.protobuf import unittest_pb2
@ -351,6 +352,200 @@ def ExpectAllFieldsAndExtensionsInOrder(serialized):
if expected != serialized:
raise ValueError('Expected %r, found %r' % (expected, serialized))
class GoldenMessageTestCase(unittest.TestCase):
"""This adds methods to TestCase useful for verifying our Golden Message."""
def ExpectAllFieldsSet(self, message):
"""Check all fields for correct values have after Set*Fields() is called."""
self.assertTrue(message.HasField('optional_int32'))
self.assertTrue(message.HasField('optional_int64'))
self.assertTrue(message.HasField('optional_uint32'))
self.assertTrue(message.HasField('optional_uint64'))
self.assertTrue(message.HasField('optional_sint32'))
self.assertTrue(message.HasField('optional_sint64'))
self.assertTrue(message.HasField('optional_fixed32'))
self.assertTrue(message.HasField('optional_fixed64'))
self.assertTrue(message.HasField('optional_sfixed32'))
self.assertTrue(message.HasField('optional_sfixed64'))
self.assertTrue(message.HasField('optional_float'))
self.assertTrue(message.HasField('optional_double'))
self.assertTrue(message.HasField('optional_bool'))
self.assertTrue(message.HasField('optional_string'))
self.assertTrue(message.HasField('optional_bytes'))
self.assertTrue(message.HasField('optionalgroup'))
self.assertTrue(message.HasField('optional_nested_message'))
self.assertTrue(message.HasField('optional_foreign_message'))
self.assertTrue(message.HasField('optional_import_message'))
self.assertTrue(message.optionalgroup.HasField('a'))
self.assertTrue(message.optional_nested_message.HasField('bb'))
self.assertTrue(message.optional_foreign_message.HasField('c'))
self.assertTrue(message.optional_import_message.HasField('d'))
self.assertTrue(message.HasField('optional_nested_enum'))
self.assertTrue(message.HasField('optional_foreign_enum'))
self.assertTrue(message.HasField('optional_import_enum'))
self.assertTrue(message.HasField('optional_string_piece'))
self.assertTrue(message.HasField('optional_cord'))
self.assertEqual(101, message.optional_int32)
self.assertEqual(102, message.optional_int64)
self.assertEqual(103, message.optional_uint32)
self.assertEqual(104, message.optional_uint64)
self.assertEqual(105, message.optional_sint32)
self.assertEqual(106, message.optional_sint64)
self.assertEqual(107, message.optional_fixed32)
self.assertEqual(108, message.optional_fixed64)
self.assertEqual(109, message.optional_sfixed32)
self.assertEqual(110, message.optional_sfixed64)
self.assertEqual(111, message.optional_float)
self.assertEqual(112, message.optional_double)
self.assertEqual(True, message.optional_bool)
self.assertEqual('115', message.optional_string)
self.assertEqual('116', message.optional_bytes)
self.assertEqual(117, message.optionalgroup.a);
self.assertEqual(118, message.optional_nested_message.bb)
self.assertEqual(119, message.optional_foreign_message.c)
self.assertEqual(120, message.optional_import_message.d)
self.assertEqual(unittest_pb2.TestAllTypes.BAZ,
message.optional_nested_enum)
self.assertEqual(unittest_pb2.FOREIGN_BAZ, message.optional_foreign_enum)
self.assertEqual(unittest_import_pb2.IMPORT_BAZ,
message.optional_import_enum)
# -----------------------------------------------------------------
self.assertEqual(2, len(message.repeated_int32))
self.assertEqual(2, len(message.repeated_int64))
self.assertEqual(2, len(message.repeated_uint32))
self.assertEqual(2, len(message.repeated_uint64))
self.assertEqual(2, len(message.repeated_sint32))
self.assertEqual(2, len(message.repeated_sint64))
self.assertEqual(2, len(message.repeated_fixed32))
self.assertEqual(2, len(message.repeated_fixed64))
self.assertEqual(2, len(message.repeated_sfixed32))
self.assertEqual(2, len(message.repeated_sfixed64))
self.assertEqual(2, len(message.repeated_float))
self.assertEqual(2, len(message.repeated_double))
self.assertEqual(2, len(message.repeated_bool))
self.assertEqual(2, len(message.repeated_string))
self.assertEqual(2, len(message.repeated_bytes))
self.assertEqual(2, len(message.repeatedgroup))
self.assertEqual(2, len(message.repeated_nested_message))
self.assertEqual(2, len(message.repeated_foreign_message))
self.assertEqual(2, len(message.repeated_import_message))
self.assertEqual(2, len(message.repeated_nested_enum))
self.assertEqual(2, len(message.repeated_foreign_enum))
self.assertEqual(2, len(message.repeated_import_enum))
self.assertEqual(2, len(message.repeated_string_piece))
self.assertEqual(2, len(message.repeated_cord))
self.assertEqual(201, message.repeated_int32[0])
self.assertEqual(202, message.repeated_int64[0])
self.assertEqual(203, message.repeated_uint32[0])
self.assertEqual(204, message.repeated_uint64[0])
self.assertEqual(205, message.repeated_sint32[0])
self.assertEqual(206, message.repeated_sint64[0])
self.assertEqual(207, message.repeated_fixed32[0])
self.assertEqual(208, message.repeated_fixed64[0])
self.assertEqual(209, message.repeated_sfixed32[0])
self.assertEqual(210, message.repeated_sfixed64[0])
self.assertEqual(211, message.repeated_float[0])
self.assertEqual(212, message.repeated_double[0])
self.assertEqual(True, message.repeated_bool[0])
self.assertEqual('215', message.repeated_string[0])
self.assertEqual('216', message.repeated_bytes[0])
self.assertEqual(217, message.repeatedgroup[0].a)
self.assertEqual(218, message.repeated_nested_message[0].bb)
self.assertEqual(219, message.repeated_foreign_message[0].c)
self.assertEqual(220, message.repeated_import_message[0].d)
self.assertEqual(unittest_pb2.TestAllTypes.BAR,
message.repeated_nested_enum[0])
self.assertEqual(unittest_pb2.FOREIGN_BAR,
message.repeated_foreign_enum[0])
self.assertEqual(unittest_import_pb2.IMPORT_BAR,
message.repeated_import_enum[0])
self.assertEqual(301, message.repeated_int32[1])
self.assertEqual(302, message.repeated_int64[1])
self.assertEqual(303, message.repeated_uint32[1])
self.assertEqual(304, message.repeated_uint64[1])
self.assertEqual(305, message.repeated_sint32[1])
self.assertEqual(306, message.repeated_sint64[1])
self.assertEqual(307, message.repeated_fixed32[1])
self.assertEqual(308, message.repeated_fixed64[1])
self.assertEqual(309, message.repeated_sfixed32[1])
self.assertEqual(310, message.repeated_sfixed64[1])
self.assertEqual(311, message.repeated_float[1])
self.assertEqual(312, message.repeated_double[1])
self.assertEqual(False, message.repeated_bool[1])
self.assertEqual('315', message.repeated_string[1])
self.assertEqual('316', message.repeated_bytes[1])
self.assertEqual(317, message.repeatedgroup[1].a)
self.assertEqual(318, message.repeated_nested_message[1].bb)
self.assertEqual(319, message.repeated_foreign_message[1].c)
self.assertEqual(320, message.repeated_import_message[1].d)
self.assertEqual(unittest_pb2.TestAllTypes.BAZ,
message.repeated_nested_enum[1])
self.assertEqual(unittest_pb2.FOREIGN_BAZ,
message.repeated_foreign_enum[1])
self.assertEqual(unittest_import_pb2.IMPORT_BAZ,
message.repeated_import_enum[1])
# -----------------------------------------------------------------
self.assertTrue(message.HasField('default_int32'))
self.assertTrue(message.HasField('default_int64'))
self.assertTrue(message.HasField('default_uint32'))
self.assertTrue(message.HasField('default_uint64'))
self.assertTrue(message.HasField('default_sint32'))
self.assertTrue(message.HasField('default_sint64'))
self.assertTrue(message.HasField('default_fixed32'))
self.assertTrue(message.HasField('default_fixed64'))
self.assertTrue(message.HasField('default_sfixed32'))
self.assertTrue(message.HasField('default_sfixed64'))
self.assertTrue(message.HasField('default_float'))
self.assertTrue(message.HasField('default_double'))
self.assertTrue(message.HasField('default_bool'))
self.assertTrue(message.HasField('default_string'))
self.assertTrue(message.HasField('default_bytes'))
self.assertTrue(message.HasField('default_nested_enum'))
self.assertTrue(message.HasField('default_foreign_enum'))
self.assertTrue(message.HasField('default_import_enum'))
self.assertEqual(401, message.default_int32)
self.assertEqual(402, message.default_int64)
self.assertEqual(403, message.default_uint32)
self.assertEqual(404, message.default_uint64)
self.assertEqual(405, message.default_sint32)
self.assertEqual(406, message.default_sint64)
self.assertEqual(407, message.default_fixed32)
self.assertEqual(408, message.default_fixed64)
self.assertEqual(409, message.default_sfixed32)
self.assertEqual(410, message.default_sfixed64)
self.assertEqual(411, message.default_float)
self.assertEqual(412, message.default_double)
self.assertEqual(False, message.default_bool)
self.assertEqual('415', message.default_string)
self.assertEqual('416', message.default_bytes)
self.assertEqual(unittest_pb2.TestAllTypes.FOO, message.default_nested_enum)
self.assertEqual(unittest_pb2.FOREIGN_FOO, message.default_foreign_enum)
self.assertEqual(unittest_import_pb2.IMPORT_FOO,
message.default_import_enum)
def GoldenFile(filename):
"""Finds the given golden file and returns a file object representing it."""
@ -359,7 +554,8 @@ def GoldenFile(filename):
while os.path.exists(path):
if os.path.exists(os.path.join(path, 'src/google/protobuf')):
# Found it. Load the golden file from the testdata directory.
return file(os.path.join(path, 'src/google/protobuf/testdata', filename))
full_path = os.path.join(path, 'src/google/protobuf/testdata', filename)
return open(full_path, 'rb')
path = os.path.join(path, '..')
raise RuntimeError(

View File

@ -42,11 +42,16 @@ from google.protobuf.internal import test_util
from google.protobuf import unittest_pb2
from google.protobuf import unittest_mset_pb2
class TextFormatTest(unittest.TestCase):
def CompareToGoldenFile(self, text, golden_filename):
class TextFormatTest(test_util.GoldenMessageTestCase):
def ReadGolden(self, golden_filename):
f = test_util.GoldenFile(golden_filename)
golden_lines = f.readlines()
f.close()
return golden_lines
def CompareToGoldenFile(self, text, golden_filename):
golden_lines = self.ReadGolden(golden_filename)
self.CompareToGoldenLines(text, golden_lines)
def CompareToGoldenText(self, text, golden_text):
@ -117,6 +122,276 @@ class TextFormatTest(unittest.TestCase):
return text.replace('e+0','e+').replace('e+0','e+') \
.replace('e-0','e-').replace('e-0','e-')
def testMergeGolden(self):
golden_text = '\n'.join(self.ReadGolden('text_format_unittest_data.txt'))
parsed_message = unittest_pb2.TestAllTypes()
text_format.Merge(golden_text, parsed_message)
message = unittest_pb2.TestAllTypes()
test_util.SetAllFields(message)
self.assertEquals(message, parsed_message)
def testMergeGoldenExtensions(self):
golden_text = '\n'.join(self.ReadGolden(
'text_format_unittest_extensions_data.txt'))
parsed_message = unittest_pb2.TestAllExtensions()
text_format.Merge(golden_text, parsed_message)
message = unittest_pb2.TestAllExtensions()
test_util.SetAllExtensions(message)
self.assertEquals(message, parsed_message)
def testMergeAllFields(self):
message = unittest_pb2.TestAllTypes()
test_util.SetAllFields(message)
ascii_text = text_format.MessageToString(message)
parsed_message = unittest_pb2.TestAllTypes()
text_format.Merge(ascii_text, parsed_message)
self.assertEqual(message, parsed_message)
self.ExpectAllFieldsSet(message)
def testMergeAllExtensions(self):
message = unittest_pb2.TestAllExtensions()
test_util.SetAllExtensions(message)
ascii_text = text_format.MessageToString(message)
parsed_message = unittest_pb2.TestAllExtensions()
text_format.Merge(ascii_text, parsed_message)
self.assertEqual(message, parsed_message)
def testMergeMessageSet(self):
message = unittest_pb2.TestAllTypes()
text = ('repeated_uint64: 1\n'
'repeated_uint64: 2\n')
text_format.Merge(text, message)
self.assertEqual(1, message.repeated_uint64[0])
self.assertEqual(2, message.repeated_uint64[1])
message = unittest_mset_pb2.TestMessageSetContainer()
text = ('message_set {\n'
' [protobuf_unittest.TestMessageSetExtension1] {\n'
' i: 23\n'
' }\n'
' [protobuf_unittest.TestMessageSetExtension2] {\n'
' str: \"foo\"\n'
' }\n'
'}\n')
text_format.Merge(text, message)
ext1 = unittest_mset_pb2.TestMessageSetExtension1.message_set_extension
ext2 = unittest_mset_pb2.TestMessageSetExtension2.message_set_extension
self.assertEquals(23, message.message_set.Extensions[ext1].i)
self.assertEquals('foo', message.message_set.Extensions[ext2].str)
def testMergeExotic(self):
message = unittest_pb2.TestAllTypes()
text = ('repeated_int64: -9223372036854775808\n'
'repeated_uint64: 18446744073709551615\n'
'repeated_double: 123.456\n'
'repeated_double: 1.23e+22\n'
'repeated_double: 1.23e-18\n'
'repeated_string: \n'
'\"\\000\\001\\007\\010\\014\\n\\r\\t\\013\\\\\\\'\\\"\"\n')
text_format.Merge(text, message)
self.assertEqual(-9223372036854775808, message.repeated_int64[0])
self.assertEqual(18446744073709551615, message.repeated_uint64[0])
self.assertEqual(123.456, message.repeated_double[0])
self.assertEqual(1.23e22, message.repeated_double[1])
self.assertEqual(1.23e-18, message.repeated_double[2])
self.assertEqual(
'\000\001\a\b\f\n\r\t\v\\\'\"', message.repeated_string[0])
def testMergeUnknownField(self):
message = unittest_pb2.TestAllTypes()
text = 'unknown_field: 8\n'
self.assertRaisesWithMessage(
text_format.ParseError,
('1:1 : Message type "protobuf_unittest.TestAllTypes" has no field named '
'"unknown_field".'),
text_format.Merge, text, message)
def testMergeBadExtension(self):
message = unittest_pb2.TestAllTypes()
text = '[unknown_extension]: 8\n'
self.assertRaisesWithMessage(
text_format.ParseError,
'1:2 : Extension "unknown_extension" not registered.',
text_format.Merge, text, message)
def testMergeGroupNotClosed(self):
message = unittest_pb2.TestAllTypes()
text = 'RepeatedGroup: <'
self.assertRaisesWithMessage(
text_format.ParseError, '1:16 : Expected ">".',
text_format.Merge, text, message)
text = 'RepeatedGroup: {'
self.assertRaisesWithMessage(
text_format.ParseError, '1:16 : Expected "}".',
text_format.Merge, text, message)
def testMergeBadEnumValue(self):
message = unittest_pb2.TestAllTypes()
text = 'optional_nested_enum: BARR'
self.assertRaisesWithMessage(
text_format.ParseError,
('1:23 : Enum type "protobuf_unittest.TestAllTypes.NestedEnum" '
'has no value named BARR.'),
text_format.Merge, text, message)
message = unittest_pb2.TestAllTypes()
text = 'optional_nested_enum: 100'
self.assertRaisesWithMessage(
text_format.ParseError,
('1:23 : Enum type "protobuf_unittest.TestAllTypes.NestedEnum" '
'has no value with number 100.'),
text_format.Merge, text, message)
def assertRaisesWithMessage(self, e_class, e, func, *args, **kwargs):
"""Same as assertRaises, but also compares the exception message."""
if hasattr(e_class, '__name__'):
exc_name = e_class.__name__
else:
exc_name = str(e_class)
try:
func(*args, **kwargs)
except e_class, expr:
if str(expr) != e:
msg = '%s raised, but with wrong message: "%s" instead of "%s"'
raise self.failureException(msg % (exc_name,
str(expr).encode('string_escape'),
e.encode('string_escape')))
return
else:
raise self.failureException('%s not raised' % exc_name)
class TokenizerTest(unittest.TestCase):
def testSimpleTokenCases(self):
text = ('identifier1:"string1"\n \n\n'
'identifier2 : \n \n123 \n identifier3 :\'string\'\n'
'identifiER_4 : 1.1e+2 ID5:-0.23 ID6:\'aaaa\\\'bbbb\'\n'
'ID7 : "aa\\"bb"\n\n\n\n ID8: {A:inf B:-inf C:true D:false}\n'
'ID9: 22 ID10: -111111111111111111 ID11: -22\n'
'ID12: 2222222222222222222')
tokenizer = text_format._Tokenizer(text)
methods = [(tokenizer.ConsumeIdentifier, 'identifier1'),
':',
(tokenizer.ConsumeString, 'string1'),
(tokenizer.ConsumeIdentifier, 'identifier2'),
':',
(tokenizer.ConsumeInt32, 123),
(tokenizer.ConsumeIdentifier, 'identifier3'),
':',
(tokenizer.ConsumeString, 'string'),
(tokenizer.ConsumeIdentifier, 'identifiER_4'),
':',
(tokenizer.ConsumeFloat, 1.1e+2),
(tokenizer.ConsumeIdentifier, 'ID5'),
':',
(tokenizer.ConsumeFloat, -0.23),
(tokenizer.ConsumeIdentifier, 'ID6'),
':',
(tokenizer.ConsumeString, 'aaaa\'bbbb'),
(tokenizer.ConsumeIdentifier, 'ID7'),
':',
(tokenizer.ConsumeString, 'aa\"bb'),
(tokenizer.ConsumeIdentifier, 'ID8'),
':',
'{',
(tokenizer.ConsumeIdentifier, 'A'),
':',
(tokenizer.ConsumeFloat, float('inf')),
(tokenizer.ConsumeIdentifier, 'B'),
':',
(tokenizer.ConsumeFloat, float('-inf')),
(tokenizer.ConsumeIdentifier, 'C'),
':',
(tokenizer.ConsumeBool, True),
(tokenizer.ConsumeIdentifier, 'D'),
':',
(tokenizer.ConsumeBool, False),
'}',
(tokenizer.ConsumeIdentifier, 'ID9'),
':',
(tokenizer.ConsumeUint32, 22),
(tokenizer.ConsumeIdentifier, 'ID10'),
':',
(tokenizer.ConsumeInt64, -111111111111111111),
(tokenizer.ConsumeIdentifier, 'ID11'),
':',
(tokenizer.ConsumeInt32, -22),
(tokenizer.ConsumeIdentifier, 'ID12'),
':',
(tokenizer.ConsumeUint64, 2222222222222222222)]
i = 0
while not tokenizer.AtEnd():
m = methods[i]
if type(m) == str:
token = tokenizer.token
self.assertEqual(token, m)
tokenizer.NextToken()
else:
self.assertEqual(m[1], m[0]())
i += 1
def testConsumeIntegers(self):
# This test only tests the failures in the integer parsing methods as well
# as the '0' special cases.
int64_max = (1 << 63) - 1
uint32_max = (1 << 32) - 1
text = '-1 %d %d' % (uint32_max + 1, int64_max + 1)
tokenizer = text_format._Tokenizer(text)
self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint32)
self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint64)
self.assertEqual(-1, tokenizer.ConsumeInt32())
self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint32)
self.assertRaises(text_format.ParseError, tokenizer.ConsumeInt32)
self.assertEqual(uint32_max + 1, tokenizer.ConsumeInt64())
self.assertRaises(text_format.ParseError, tokenizer.ConsumeInt64)
self.assertEqual(int64_max + 1, tokenizer.ConsumeUint64())
self.assertTrue(tokenizer.AtEnd())
text = '-0 -0 0 0'
tokenizer = text_format._Tokenizer(text)
self.assertEqual(0, tokenizer.ConsumeUint32())
self.assertEqual(0, tokenizer.ConsumeUint64())
self.assertEqual(0, tokenizer.ConsumeUint32())
self.assertEqual(0, tokenizer.ConsumeUint64())
self.assertTrue(tokenizer.AtEnd())
def testConsumeByteString(self):
text = '"string1\''
tokenizer = text_format._Tokenizer(text)
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
text = 'string1"'
tokenizer = text_format._Tokenizer(text)
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
text = '\n"\\xt"'
tokenizer = text_format._Tokenizer(text)
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
text = '\n"\\"'
tokenizer = text_format._Tokenizer(text)
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
text = '\n"\\x"'
tokenizer = text_format._Tokenizer(text)
self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
def testConsumeBool(self):
text = 'not-a-bool'
tokenizer = text_format._Tokenizer(text)
self.assertRaises(text_format.ParseError, tokenizer.ConsumeBool)
if __name__ == '__main__':
unittest.main()

View File

@ -122,8 +122,10 @@ class UnicodeValueChecker(object):
try:
unicode(proposed_value, 'ascii')
except UnicodeDecodeError:
raise ValueError('%.1024r isn\'t in 7-bit ASCII encoding.'
% (proposed_value))
raise ValueError('%.1024r has type str, but isn\'t in 7-bit ASCII '
'encoding. Non-ASCII strings must be converted to '
'unicode objects before being added.' %
(proposed_value))
class Int32ValueChecker(IntValueChecker):

View File

@ -64,6 +64,8 @@ UINT64_MAX = (1 << 64) - 1
# "struct" format strings that will encode/decode the specified formats.
FORMAT_UINT32_LITTLE_ENDIAN = '<I'
FORMAT_UINT64_LITTLE_ENDIAN = '<Q'
FORMAT_FLOAT_LITTLE_ENDIAN = '<f'
FORMAT_DOUBLE_LITTLE_ENDIAN = '<d'
# We'll have to provide alternate implementations of AppendLittleEndian*() on

View File

@ -36,7 +36,6 @@
__author__ = 'robinson@google.com (Will Robinson)'
from google.protobuf import text_format
class Error(Exception): pass
class DecodeError(Error): pass
@ -76,7 +75,7 @@ class Message(object):
return not self == other_msg
def __str__(self):
return text_format.MessageToString(self)
raise NotImplementedError
def MergeFrom(self, other_msg):
"""Merges the contents of the specified message into current message.

View File

@ -62,6 +62,7 @@ from google.protobuf.internal import type_checkers
from google.protobuf.internal import wire_format
from google.protobuf import descriptor as descriptor_mod
from google.protobuf import message as message_mod
from google.protobuf import text_format
_FieldDescriptor = descriptor_mod.FieldDescriptor
@ -291,7 +292,7 @@ def _DefaultValueForField(message, field):
def _AddInitMethod(message_descriptor, cls):
"""Adds an __init__ method to cls."""
fields = message_descriptor.fields
def init(self):
def init(self, **kwargs):
self._cached_byte_size = 0
self._cached_byte_size_dirty = False
self._listener = message_listener_mod.NullMessageListener()
@ -306,12 +307,30 @@ def _AddInitMethod(message_descriptor, cls):
if field.label != _FieldDescriptor.LABEL_REPEATED:
setattr(self, _HasFieldName(field.name), False)
self.Extensions = _ExtensionDict(self, cls._known_extensions)
for field_name, field_value in kwargs.iteritems():
field = _GetFieldByName(message_descriptor, field_name)
_MergeFieldOrExtension(self, field, field_value)
init.__module__ = None
init.__doc__ = None
cls.__init__ = init
def _GetFieldByName(message_descriptor, field_name):
"""Returns a field descriptor by field name.
Args:
message_descriptor: A Descriptor describing all fields in message.
field_name: The name of the field to retrieve.
Returns:
The field descriptor associated with the field name.
"""
try:
return message_descriptor.fields_by_name[field_name]
except KeyError:
raise ValueError('Protocol message has no "%s" field.' % field_name)
def _AddPropertiesForFields(descriptor, cls):
"""Adds properties for all fields in this protocol message type."""
for field in descriptor.fields:
@ -543,10 +562,7 @@ def _AddHasFieldMethod(cls):
def _AddClearFieldMethod(cls):
"""Helper for _AddMessageMethods()."""
def ClearField(self, field_name):
try:
field = self.DESCRIPTOR.fields_by_name[field_name]
except KeyError:
raise ValueError('Protocol message has no "%s" field.' % field_name)
field = _GetFieldByName(self.DESCRIPTOR, field_name)
proto_field_name = field.name
python_field_name = _ValueFieldName(proto_field_name)
has_field_name = _HasFieldName(proto_field_name)
@ -629,6 +645,13 @@ def _AddEqualsMethod(message_descriptor, cls):
cls.__eq__ = __eq__
def _AddStrMethod(message_descriptor, cls):
"""Helper for _AddMessageMethods()."""
def __str__(self):
return text_format.MessageToString(self)
cls.__str__ = __str__
def _AddSetListenerMethod(cls):
"""Helper for _AddMessageMethods()."""
def SetListener(self, listener):
@ -1090,7 +1113,7 @@ def _DeserializeOneEntity(message_descriptor, message, decoder):
content_start = decoder.Position()
while decoder.Position() - content_start < length:
element_list.append(_DeserializeScalarFromDecoder(field_type, decoder))
return decoder.Position() - content_start
return decoder.Position() - initial_position
else:
# Repeated composite.
composite = element_list.add()
@ -1275,6 +1298,7 @@ def _AddMessageMethods(message_descriptor, cls):
_AddClearMethod(cls)
_AddHasExtensionMethod(cls)
_AddEqualsMethod(message_descriptor, cls)
_AddStrMethod(message_descriptor, cls)
_AddSetListenerMethod(cls)
_AddByteSizeMethod(message_descriptor, cls)
_AddSerializeToStringMethod(message_descriptor, cls)
@ -1436,6 +1460,20 @@ class _ExtensionDict(object):
if extension.label != _FieldDescriptor.LABEL_REPEATED)
self._has_bits = dict.fromkeys(keys, False)
self._extensions_by_number = dict(
(f.number, f) for f in self._known_extensions.itervalues())
self._extensions_by_name = {}
for extension in self._known_extensions.itervalues():
if (extension.containing_type.GetOptions().message_set_wire_format and
extension.type == descriptor_mod.FieldDescriptor.TYPE_MESSAGE and
extension.message_type == extension.extension_scope and
extension.label == descriptor_mod.FieldDescriptor.LABEL_OPTIONAL):
extension_name = extension.message_type.full_name
else:
extension_name = extension.full_name
self._extensions_by_name[extension_name] = extension
def __getitem__(self, extension_handle):
"""Returns the current value of the given extension handle."""
# We don't care as much about keeping critical sections short in the
@ -1609,7 +1647,15 @@ class _ExtensionDict(object):
Returns: A dict mapping field_number to (handle, field_descriptor),
for *all* registered extensions for this dict.
"""
# TODO(robinson): Precompute and store this away. Note that we'll have to
# be careful when we move away from having _known_extensions as a
# deep-copied member of this object.
return dict((f.number, f) for f in self._known_extensions.itervalues())
return self._extensions_by_number
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._extensions_by_name.get(name, None)

View File

@ -67,8 +67,6 @@ class Service(object):
and "done" will later be called with the response value.
In the blocking case, RpcException will be raised on error.
Asynchronous calls must check status via the Failed method of the
RpcController.
Preconditions:
* method_descriptor.service == GetDescriptor
@ -82,6 +80,9 @@ class Service(object):
Postconditions:
* "done" will be called when the method is complete. This may be
before CallMethod() returns or it may be at some point in the future.
* If the RPC failed, the response value passed to "done" will be None.
Further details about the failure can be found by querying the
RpcController.
"""
raise NotImplementedError

View File

@ -33,10 +33,19 @@
__author__ = 'kenton@google.com (Kenton Varda)'
import cStringIO
import re
from collections import deque
from google.protobuf.internal import type_checkers
from google.protobuf import descriptor
__all__ = [ 'MessageToString', 'PrintMessage', 'PrintField', 'PrintFieldValue' ]
__all__ = [ 'MessageToString', 'PrintMessage', 'PrintField',
'PrintFieldValue', 'Merge' ]
class ParseError(Exception):
"""Thrown in case of ASCII parsing error."""
def MessageToString(message):
out = cStringIO.StringIO()
@ -45,6 +54,7 @@ def MessageToString(message):
out.close()
return result
def PrintMessage(message, out, indent = 0):
for field, value in message.ListFields():
if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
@ -53,6 +63,7 @@ def PrintMessage(message, out, indent = 0):
else:
PrintField(field, value, out, indent)
def PrintField(field, value, out, indent = 0):
"""Print a single field name/value pair. For repeated fields, the value
should be a single element."""
@ -82,6 +93,7 @@ def PrintField(field, value, out, indent = 0):
PrintFieldValue(field, value, out, indent)
out.write('\n')
def PrintFieldValue(field, value, out, indent = 0):
"""Print a single field value (not including name). For repeated fields,
the value should be a single element."""
@ -104,6 +116,507 @@ def PrintFieldValue(field, value, out, indent = 0):
else:
out.write(str(value))
def Merge(text, message):
"""Merges an ASCII representation of a protocol message into a message.
Args:
text: Message ASCII representation.
message: A protocol buffer message to merge into.
Raises:
ParseError: On ASCII parsing problems.
"""
tokenizer = _Tokenizer(text)
while not tokenizer.AtEnd():
_MergeField(tokenizer, message)
def _MergeField(tokenizer, message):
"""Merges a single protocol message field into a message.
Args:
tokenizer: A tokenizer to parse the field name and values.
message: A protocol message to record the data.
Raises:
ParseError: In case of ASCII parsing problems.
"""
message_descriptor = message.DESCRIPTOR
if tokenizer.TryConsume('['):
name = [tokenizer.ConsumeIdentifier()]
while tokenizer.TryConsume('.'):
name.append(tokenizer.ConsumeIdentifier())
name = '.'.join(name)
field = message.Extensions._FindExtensionByName(name)
if not field:
raise tokenizer.ParseErrorPreviousToken(
'Extension "%s" not registered.' % name)
elif message_descriptor != field.containing_type:
raise tokenizer.ParseErrorPreviousToken(
'Extension "%s" does not extend message type "%s".' % (
name, message_descriptor.full_name))
tokenizer.Consume(']')
else:
name = tokenizer.ConsumeIdentifier()
field = message_descriptor.fields_by_name.get(name, None)
# Group names are expected to be capitalized as they appear in the
# .proto file, which actually matches their type names, not their field
# names.
if not field:
field = message_descriptor.fields_by_name.get(name.lower(), None)
if field and field.type != descriptor.FieldDescriptor.TYPE_GROUP:
field = None
if (field and field.type == descriptor.FieldDescriptor.TYPE_GROUP and
field.message_type.name != name):
field = None
if not field:
raise tokenizer.ParseErrorPreviousToken(
'Message type "%s" has no field named "%s".' % (
message_descriptor.full_name, name))
if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
tokenizer.TryConsume(':')
if tokenizer.TryConsume('<'):
end_token = '>'
else:
tokenizer.Consume('{')
end_token = '}'
if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
if field.is_extension:
sub_message = message.Extensions[field].add()
else:
sub_message = getattr(message, field.name).add()
else:
if field.is_extension:
sub_message = message.Extensions[field]
else:
sub_message = getattr(message, field.name)
while not tokenizer.TryConsume(end_token):
if tokenizer.AtEnd():
raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token))
_MergeField(tokenizer, sub_message)
else:
_MergeScalarField(tokenizer, message, field)
def _MergeScalarField(tokenizer, message, field):
"""Merges a single protocol message scalar field into a message.
Args:
tokenizer: A tokenizer to parse the field value.
message: A protocol message to record the data.
field: The descriptor of the field to be merged.
Raises:
ParseError: In case of ASCII parsing problems.
RuntimeError: On runtime errors.
"""
tokenizer.Consume(':')
value = None
if field.type in (descriptor.FieldDescriptor.TYPE_INT32,
descriptor.FieldDescriptor.TYPE_SINT32,
descriptor.FieldDescriptor.TYPE_SFIXED32):
value = tokenizer.ConsumeInt32()
elif field.type in (descriptor.FieldDescriptor.TYPE_INT64,
descriptor.FieldDescriptor.TYPE_SINT64,
descriptor.FieldDescriptor.TYPE_SFIXED64):
value = tokenizer.ConsumeInt64()
elif field.type in (descriptor.FieldDescriptor.TYPE_UINT32,
descriptor.FieldDescriptor.TYPE_FIXED32):
value = tokenizer.ConsumeUint32()
elif field.type in (descriptor.FieldDescriptor.TYPE_UINT64,
descriptor.FieldDescriptor.TYPE_FIXED64):
value = tokenizer.ConsumeUint64()
elif field.type in (descriptor.FieldDescriptor.TYPE_FLOAT,
descriptor.FieldDescriptor.TYPE_DOUBLE):
value = tokenizer.ConsumeFloat()
elif field.type == descriptor.FieldDescriptor.TYPE_BOOL:
value = tokenizer.ConsumeBool()
elif field.type == descriptor.FieldDescriptor.TYPE_STRING:
value = tokenizer.ConsumeString()
elif field.type == descriptor.FieldDescriptor.TYPE_BYTES:
value = tokenizer.ConsumeByteString()
elif field.type == descriptor.FieldDescriptor.TYPE_ENUM:
# Enum can be specified by a number (the enum value), or by
# a string literal (the enum name).
enum_descriptor = field.enum_type
if tokenizer.LookingAtInteger():
number = tokenizer.ConsumeInt32()
enum_value = enum_descriptor.values_by_number.get(number, None)
if enum_value is None:
raise tokenizer.ParseErrorPreviousToken(
'Enum type "%s" has no value with number %d.' % (
enum_descriptor.full_name, number))
else:
identifier = tokenizer.ConsumeIdentifier()
enum_value = enum_descriptor.values_by_name.get(identifier, None)
if enum_value is None:
raise tokenizer.ParseErrorPreviousToken(
'Enum type "%s" has no value named %s.' % (
enum_descriptor.full_name, identifier))
value = enum_value.number
else:
raise RuntimeError('Unknown field type %d' % field.type)
if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
if field.is_extension:
message.Extensions[field].append(value)
else:
getattr(message, field.name).append(value)
else:
if field.is_extension:
message.Extensions[field] = value
else:
setattr(message, field.name, value)
class _Tokenizer(object):
"""Protocol buffer ASCII representation tokenizer.
This class handles the lower level string parsing by splitting it into
meaningful tokens.
It was directly ported from the Java protocol buffer API.
"""
_WHITESPACE = re.compile('(\\s|(#.*$))+', re.MULTILINE)
_TOKEN = re.compile(
'[a-zA-Z_][0-9a-zA-Z_+-]*|' # an identifier
'[0-9+-][0-9a-zA-Z_.+-]*|' # a number
'\"([^\"\n\\\\]|\\\\.)*(\"|\\\\?$)|' # a double-quoted string
'\'([^\"\n\\\\]|\\\\.)*(\'|\\\\?$)') # a single-quoted string
_IDENTIFIER = re.compile('\w+')
_INTEGER_CHECKERS = [type_checkers.Uint32ValueChecker(),
type_checkers.Int32ValueChecker(),
type_checkers.Uint64ValueChecker(),
type_checkers.Int64ValueChecker()]
_FLOAT_INFINITY = re.compile('-?inf(inity)?f?', re.IGNORECASE)
_FLOAT_NAN = re.compile("nanf?", re.IGNORECASE)
def __init__(self, text_message):
self._text_message = text_message
self._position = 0
self._line = -1
self._column = 0
self._token_start = None
self.token = ''
self._lines = deque(text_message.split('\n'))
self._current_line = ''
self._previous_line = 0
self._previous_column = 0
self._SkipWhitespace()
self.NextToken()
def AtEnd(self):
"""Checks the end of the text was reached.
Returns:
True iff the end was reached.
"""
return not self._lines and not self._current_line
def _PopLine(self):
while not self._current_line:
if not self._lines:
self._current_line = ''
return
self._line += 1
self._column = 0
self._current_line = self._lines.popleft()
def _SkipWhitespace(self):
while True:
self._PopLine()
match = re.match(self._WHITESPACE, self._current_line)
if not match:
break
length = len(match.group(0))
self._current_line = self._current_line[length:]
self._column += length
def TryConsume(self, token):
"""Tries to consume a given piece of text.
Args:
token: Text to consume.
Returns:
True iff the text was consumed.
"""
if self.token == token:
self.NextToken()
return True
return False
def Consume(self, token):
"""Consumes a piece of text.
Args:
token: Text to consume.
Raises:
ParseError: If the text couldn't be consumed.
"""
if not self.TryConsume(token):
raise self._ParseError('Expected "%s".' % token)
def LookingAtInteger(self):
"""Checks if the current token is an integer.
Returns:
True iff the current token is an integer.
"""
if not self.token:
return False
c = self.token[0]
return (c >= '0' and c <= '9') or c == '-' or c == '+'
def ConsumeIdentifier(self):
"""Consumes protocol message field identifier.
Returns:
Identifier string.
Raises:
ParseError: If an identifier couldn't be consumed.
"""
result = self.token
if not re.match(self._IDENTIFIER, result):
raise self._ParseError('Expected identifier.')
self.NextToken()
return result
def ConsumeInt32(self):
"""Consumes a signed 32bit integer number.
Returns:
The integer parsed.
Raises:
ParseError: If a signed 32bit integer couldn't be consumed.
"""
try:
result = self._ParseInteger(self.token, is_signed=True, is_long=False)
except ValueError, e:
raise self._IntegerParseError(e)
self.NextToken()
return result
def ConsumeUint32(self):
"""Consumes an unsigned 32bit integer number.
Returns:
The integer parsed.
Raises:
ParseError: If an unsigned 32bit integer couldn't be consumed.
"""
try:
result = self._ParseInteger(self.token, is_signed=False, is_long=False)
except ValueError, e:
raise self._IntegerParseError(e)
self.NextToken()
return result
def ConsumeInt64(self):
"""Consumes a signed 64bit integer number.
Returns:
The integer parsed.
Raises:
ParseError: If a signed 64bit integer couldn't be consumed.
"""
try:
result = self._ParseInteger(self.token, is_signed=True, is_long=True)
except ValueError, e:
raise self._IntegerParseError(e)
self.NextToken()
return result
def ConsumeUint64(self):
"""Consumes an unsigned 64bit integer number.
Returns:
The integer parsed.
Raises:
ParseError: If an unsigned 64bit integer couldn't be consumed.
"""
try:
result = self._ParseInteger(self.token, is_signed=False, is_long=True)
except ValueError, e:
raise self._IntegerParseError(e)
self.NextToken()
return result
def ConsumeFloat(self):
"""Consumes an floating point number.
Returns:
The number parsed.
Raises:
ParseError: If a floating point number couldn't be consumed.
"""
text = self.token
if re.match(self._FLOAT_INFINITY, text):
self.NextToken()
if text.startswith('-'):
return float('-inf')
return float('inf')
if re.match(self._FLOAT_NAN, text):
self.NextToken()
return float('nan')
try:
result = float(text)
except ValueError, e:
raise self._FloatParseError(e)
self.NextToken()
return result
def ConsumeBool(self):
"""Consumes a boolean value.
Returns:
The bool parsed.
Raises:
ParseError: If a boolean value couldn't be consumed.
"""
if self.token == 'true':
self.NextToken()
return True
elif self.token == 'false':
self.NextToken()
return False
else:
raise self._ParseError('Expected "true" or "false".')
def ConsumeString(self):
"""Consumes a string value.
Returns:
The string parsed.
Raises:
ParseError: If a string value couldn't be consumed.
"""
return unicode(self.ConsumeByteString(), 'utf-8')
def ConsumeByteString(self):
"""Consumes a byte array value.
Returns:
The array parsed (as a string).
Raises:
ParseError: If a byte array value couldn't be consumed.
"""
text = self.token
if len(text) < 1 or text[0] not in ('\'', '"'):
raise self._ParseError('Exptected string.')
if len(text) < 2 or text[-1] != text[0]:
raise self._ParseError('String missing ending quote.')
try:
result = _CUnescape(text[1:-1])
except ValueError, e:
raise self._ParseError(str(e))
self.NextToken()
return result
def _ParseInteger(self, text, is_signed=False, is_long=False):
"""Parses an integer.
Args:
text: The text to parse.
is_signed: True if a signed integer must be parsed.
is_long: True if a long integer must be parsed.
Returns:
The integer value.
Raises:
ValueError: Thrown Iff the text is not a valid integer.
"""
pos = 0
if text.startswith('-'):
pos += 1
base = 10
if text.startswith('0x', pos) or text.startswith('0X', pos):
base = 16
elif text.startswith('0', pos):
base = 8
# Do the actual parsing. Exception handling is propagated to caller.
result = int(text, base)
# Check if the integer is sane. Exceptions handled by callers.
checker = self._INTEGER_CHECKERS[2 * int(is_long) + int(is_signed)]
checker.CheckValue(result)
return result
def ParseErrorPreviousToken(self, message):
"""Creates and *returns* a ParseError for the previously read token.
Args:
message: A message to set for the exception.
Returns:
A ParseError instance.
"""
return ParseError('%d:%d : %s' % (
self._previous_line + 1, self._previous_column + 1, message))
def _ParseError(self, message):
"""Creates and *returns* a ParseError for the current token."""
return ParseError('%d:%d : %s' % (
self._line + 1, self._column + 1, message))
def _IntegerParseError(self, e):
return self._ParseError('Couldn\'t parse integer: ' + str(e))
def _FloatParseError(self, e):
return self._ParseError('Couldn\'t parse number: ' + str(e))
def NextToken(self):
"""Reads the next meaningful token."""
self._previous_line = self._line
self._previous_column = self._column
if self.AtEnd():
self.token = ''
return
self._column += len(self.token)
# Make sure there is data to work on.
self._PopLine()
match = re.match(self._TOKEN, self._current_line)
if match:
token = match.group(0)
self._current_line = self._current_line[len(token):]
self.token = token
else:
self.token = self._current_line[0]
self._current_line = self._current_line[1:]
self._SkipWhitespace()
# text.encode('string_escape') does not seem to satisfy our needs as it
# encodes unprintable characters using two-digit hex escapes whereas our
# C++ unescaping function allows hex escapes to be any length. So,
@ -123,3 +636,15 @@ def _CEscape(text):
if o >= 127 or o < 32: return "\\%03o" % o # necessary escapes
return c
return "".join([escape(c) for c in text])
_CUNESCAPE_HEX = re.compile('\\\\x([0-9a-fA-F]{2}|[0-9a-f-A-F])')
def _CUnescape(text):
def ReplaceHex(m):
return chr(int(m.group(0)[2:], 16))
# This is required because the 'string_escape' encoding doesn't
# allow single-digit hex escapes (like '\xf').
result = _CUNESCAPE_HEX.sub(ReplaceHex, text)
return result.decode('string_escape')

View File

@ -43,21 +43,25 @@ nobase_include_HEADERS = \
google/protobuf/descriptor_database.h \
google/protobuf/dynamic_message.h \
google/protobuf/extension_set.h \
google/protobuf/generated_message_util.h \
google/protobuf/generated_message_reflection.h \
google/protobuf/message.h \
google/protobuf/message_lite.h \
google/protobuf/reflection_ops.h \
google/protobuf/repeated_field.h \
google/protobuf/service.h \
google/protobuf/text_format.h \
google/protobuf/unknown_field_set.h \
google/protobuf/wire_format.h \
google/protobuf/wire_format_inl.h \
google/protobuf/wire_format_lite.h \
google/protobuf/wire_format_lite_inl.h \
google/protobuf/io/coded_stream.h \
$(GZHEADERS) \
google/protobuf/io/printer.h \
google/protobuf/io/tokenizer.h \
google/protobuf/io/zero_copy_stream.h \
google/protobuf/io/zero_copy_stream_impl.h \
google/protobuf/io/zero_copy_stream_impl_lite.h \
google/protobuf/compiler/code_generator.h \
google/protobuf/compiler/command_line_interface.h \
google/protobuf/compiler/importer.h \
@ -68,6 +72,8 @@ nobase_include_HEADERS = \
lib_LTLIBRARIES = libprotobuf.la libprotoc.la
# TODO(kenton): Separate lite and full libraries. Also make sure lite_unittest
# only links against the lite lib.
libprotobuf_la_LIBADD = $(PTHREAD_LIBS)
libprotobuf_la_LDFLAGS = -version-info 3:0:0
libprotobuf_la_SOURCES = \
@ -89,20 +95,25 @@ libprotobuf_la_SOURCES = \
google/protobuf/descriptor_database.cc \
google/protobuf/dynamic_message.cc \
google/protobuf/extension_set.cc \
google/protobuf/extension_set_heavy.cc \
google/protobuf/generated_message_util.cc \
google/protobuf/generated_message_reflection.cc \
google/protobuf/message.cc \
google/protobuf/message_lite.cc \
google/protobuf/reflection_ops.cc \
google/protobuf/repeated_field.cc \
google/protobuf/service.cc \
google/protobuf/text_format.cc \
google/protobuf/unknown_field_set.cc \
google/protobuf/wire_format.cc \
google/protobuf/wire_format_lite.cc \
google/protobuf/io/coded_stream.cc \
google/protobuf/io/gzip_stream.cc \
google/protobuf/io/printer.cc \
google/protobuf/io/tokenizer.cc \
google/protobuf/io/zero_copy_stream.cc \
google/protobuf/io/zero_copy_stream_impl.cc \
google/protobuf/io/zero_copy_stream_impl_lite.cc \
google/protobuf/compiler/importer.cc \
google/protobuf/compiler/parser.cc
@ -171,6 +182,9 @@ protoc_inputs = \
google/protobuf/unittest_optimize_for.proto \
google/protobuf/unittest_embed_optimize_for.proto \
google/protobuf/unittest_custom_options.proto \
google/protobuf/unittest_lite.proto \
google/protobuf/unittest_import_lite.proto \
google/protobuf/unittest_lite_imports_nonlite.proto \
google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
EXTRA_DIST = \
@ -186,7 +200,14 @@ EXTRA_DIST = \
google/protobuf/io/package_info.h \
google/protobuf/compiler/package_info.h
protoc_lite_outputs = \
google/protobuf/unittest_lite.pb.cc \
google/protobuf/unittest_lite.pb.h \
google/protobuf/unittest_import_lite.pb.cc \
google/protobuf/unittest_import_lite.pb.h
protoc_outputs = \
$(protoc_lite_outputs) \
google/protobuf/unittest.pb.cc \
google/protobuf/unittest.pb.h \
google/protobuf/unittest_empty.pb.cc \
@ -201,6 +222,8 @@ protoc_outputs = \
google/protobuf/unittest_embed_optimize_for.pb.h \
google/protobuf/unittest_custom_options.pb.cc \
google/protobuf/unittest_custom_options.pb.h \
google/protobuf/unittest_lite_imports_nonlite.pb.cc \
google/protobuf/unittest_lite_imports_nonlite.pb.h \
google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc \
google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h
@ -240,7 +263,7 @@ COMMON_TEST_SOURCES = \
google/protobuf/testing/file.cc \
google/protobuf/testing/file.h
check_PROGRAMS = protobuf-test protobuf-lazy-descriptor-test $(GZCHECKPROGRAMS)
check_PROGRAMS = protobuf-test protobuf-lazy-descriptor-test protobuf-lite-test $(GZCHECKPROGRAMS)
protobuf_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la \
$(top_builddir)/gtest/lib/libgtest.la \
$(top_builddir)/gtest/lib/libgtest_main.la
@ -290,6 +313,14 @@ protobuf_lazy_descriptor_test_SOURCES = \
$(COMMON_TEST_SOURCES)
nodist_protobuf_lazy_descriptor_test_SOURCES = $(protoc_outputs)
# Build lite_unittest separately, since it doesn't use gtest.
protobuf_lite_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la
protobuf_lite_test_SOURCES = \
google/protobuf/lite_unittest.cc \
google/protobuf/test_util_lite.cc \
google/protobuf/test_util_lite.h
nodist_protobuf_lite_test_SOURCES = $(protoc_lite_outputs)
if HAVE_ZLIB
zcgzip_LDADD = $(PTHREAD_LIBS) libprotobuf.la
zcgzip_SOURCES = google/protobuf/testing/zcgzip.cc
@ -298,4 +329,4 @@ zcgunzip_LDADD = $(PTHREAD_LIBS) libprotobuf.la
zcgunzip_SOURCES = google/protobuf/testing/zcgunzip.cc
endif
TESTS = protobuf-test protobuf-lazy-descriptor-test $(GZTESTS)
TESTS = protobuf-test protobuf-lazy-descriptor-test protobuf-lite-test $(GZTESTS)

View File

@ -34,6 +34,8 @@
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
namespace compiler {
@ -41,6 +43,26 @@ namespace compiler {
CodeGenerator::~CodeGenerator() {}
OutputDirectory::~OutputDirectory() {}
// Parses a set of comma-delimited name/value pairs.
void ParseGeneratorParameter(const string& text,
vector<pair<string, string> >* output) {
vector<string> parts;
SplitStringUsing(text, ",", &parts);
for (int i = 0; i < parts.size(); i++) {
string::size_type equals_pos = parts[i].find_first_of('=');
pair<string, string> value;
if (equals_pos == string::npos) {
value.first = parts[i];
value.second = "";
} else {
value.first = parts[i].substr(0, equals_pos);
value.second = parts[i].substr(equals_pos + 1);
}
output->push_back(value);
}
}
} // namespace compiler
} // namespace protobuf
} // namespace google

View File

@ -40,6 +40,8 @@
#include <google/protobuf/stubs/common.h>
#include <string>
#include <vector>
#include <utility>
namespace google {
namespace protobuf {
@ -105,6 +107,15 @@ class LIBPROTOC_EXPORT OutputDirectory {
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OutputDirectory);
};
// Several code generators treat the parameter argument as holding a
// list of options separated by commas. This helper function parses
// a set of comma-delimited name/value pairs: e.g.,
// "foo=bar,baz,qux=corge"
// parses to the pairs:
// ("foo", "bar"), ("baz", ""), ("qux", "corge")
extern void ParseGeneratorParameter(const string&,
vector<pair<string, string> >*);
} // namespace compiler
} // namespace protobuf

View File

@ -95,24 +95,39 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
}
printer->Print(vars,
"$dllexport$const ::google::protobuf::EnumDescriptor* $classname$_descriptor();\n"
"$dllexport$bool $classname$_IsValid(int value);\n"
"const $classname$ $prefix$$short_name$_MIN = $prefix$$min_name$;\n"
"const $classname$ $prefix$$short_name$_MAX = $prefix$$max_name$;\n"
"\n");
// The _Name and _Parse methods
printer->Print(vars,
"inline const ::std::string& $classname$_Name($classname$ value) {\n"
" return ::google::protobuf::internal::NameOfEnum(\n"
" $classname$_descriptor(), value);\n"
"}\n");
printer->Print(vars,
"inline bool $classname$_Parse(\n"
" const ::std::string& name, $classname$* value) {\n"
" return ::google::protobuf::internal::ParseNamedEnum<$classname$>(\n"
" $classname$_descriptor(), name, value);\n"
"}\n");
if (HasDescriptorMethods(descriptor_->file())) {
printer->Print(vars,
"$dllexport$const ::google::protobuf::EnumDescriptor* $classname$_descriptor();\n");
// The _Name and _Parse methods
printer->Print(vars,
"inline const ::std::string& $classname$_Name($classname$ value) {\n"
" return ::google::protobuf::internal::NameOfEnum(\n"
" $classname$_descriptor(), value);\n"
"}\n");
printer->Print(vars,
"inline bool $classname$_Parse(\n"
" const ::std::string& name, $classname$* value) {\n"
" return ::google::protobuf::internal::ParseNamedEnum<$classname$>(\n"
" $classname$_descriptor(), name, value);\n"
"}\n");
}
}
void EnumGenerator::
GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
if (HasDescriptorMethods(descriptor_->file())) {
printer->Print(
"template <>\n"
"inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n"
" return $classname$_descriptor();\n"
"}\n",
"classname", ClassName(descriptor_, true));
}
}
void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
@ -128,24 +143,28 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
}
printer->Print(vars,
"static inline const ::google::protobuf::EnumDescriptor*\n"
"$nested_name$_descriptor() {\n"
" return $classname$_descriptor();\n"
"}\n"
"static inline bool $nested_name$_IsValid(int value) {\n"
" return $classname$_IsValid(value);\n"
"}\n"
"static inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n"
" return $classname$_Name(value);\n"
"}\n"
"static inline bool $nested_name$_Parse(const ::std::string& name,\n"
" $nested_name$* value) {\n"
" return $classname$_Parse(name, value);\n"
"}\n"
"static const $nested_name$ $nested_name$_MIN =\n"
" $classname$_$nested_name$_MIN;\n"
"static const $nested_name$ $nested_name$_MAX =\n"
" $classname$_$nested_name$_MAX;\n");
if (HasDescriptorMethods(descriptor_->file())) {
printer->Print(vars,
"static inline const ::google::protobuf::EnumDescriptor*\n"
"$nested_name$_descriptor() {\n"
" return $classname$_descriptor();\n"
"}\n"
"static inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n"
" return $classname$_Name(value);\n"
"}\n"
"static inline bool $nested_name$_Parse(const ::std::string& name,\n"
" $nested_name$* value) {\n"
" return $classname$_Parse(name, value);\n"
"}\n");
}
}
void EnumGenerator::GenerateDescriptorInitializer(
@ -168,11 +187,15 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) {
map<string, string> vars;
vars["classname"] = classname_;
if (HasDescriptorMethods(descriptor_->file())) {
printer->Print(vars,
"const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n"
" protobuf_AssignDescriptorsOnce();\n"
" return $classname$_descriptor_;\n"
"}\n");
}
printer->Print(vars,
"const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n"
" protobuf_AssignDescriptorsOnce();\n"
" return $classname$_descriptor_;\n"
"}\n"
"bool $classname$_IsValid(int value) {\n"
" switch(value) {\n");

View File

@ -63,6 +63,10 @@ class EnumGenerator {
// nested enums.
void GenerateDefinition(io::Printer* printer);
// Generate specialization of GetEnumDescriptor<MyEnum>().
// Precondition: in ::google::protobuf namespace.
void GenerateGetEnumDescriptorSpecializations(io::Printer* printer);
// For enums nested within a message, generate code to import all the enum's
// symbols (e.g. the enum type name, all its values, etc.) into the class's
// namespace. This should be placed inside the class definition in the

View File

@ -35,7 +35,7 @@
#include <google/protobuf/compiler/cpp/cpp_enum_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format_inl.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
@ -43,24 +43,14 @@ namespace protobuf {
namespace compiler {
namespace cpp {
using internal::WireFormat;
namespace {
// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
// repeat code between this and the other field types.
void SetEnumVariables(const FieldDescriptor* descriptor,
map<string, string>* variables) {
SetCommonFieldVariables(descriptor, variables);
const EnumValueDescriptor* default_value = descriptor->default_value_enum();
(*variables)["name"] = FieldName(descriptor);
(*variables)["type"] = ClassName(descriptor->enum_type(), true);
(*variables)["default"] = SimpleItoa(default_value->number());
(*variables)["index"] = SimpleItoa(descriptor->index());
(*variables)["number"] = SimpleItoa(descriptor->number());
(*variables)["classname"] = ClassName(FieldScope(descriptor), false);
(*variables)["tag_size"] = SimpleItoa(
WireFormat::TagSize(descriptor->number(), descriptor->type()));
}
} // namespace
@ -83,8 +73,8 @@ GeneratePrivateMembers(io::Printer* printer) const {
void EnumFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
"inline $type$ $name$() const;\n"
"inline void set_$name$($type$ value);\n");
"inline $type$ $name$() const$deprecation$;\n"
"inline void set_$name$($type$ value)$deprecation$;\n");
}
void EnumFieldGenerator::
@ -124,33 +114,37 @@ void EnumFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
printer->Print(variables_,
"int value;\n"
"DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));\n"
"DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value));\n"
"if ($type$_IsValid(value)) {\n"
" set_$name$(static_cast< $type$ >(value));\n"
"} else {\n"
" mutable_unknown_fields()->AddVarint($number$, value);\n"
" set_$name$(static_cast< $type$ >(value));\n");
if (HasUnknownFields(descriptor_->file())) {
printer->Print(variables_,
"} else {\n"
" mutable_unknown_fields()->AddVarint($number$, value);\n");
}
printer->Print(variables_,
"}\n");
}
void EnumFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::internal::WireFormat::WriteEnum("
"$number$, this->$name$(), output);\n");
"::google::protobuf::internal::WireFormatLite::WriteEnum(\n"
" $number$, this->$name$(), output);\n");
}
void EnumFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
printer->Print(variables_,
"target = ::google::protobuf::internal::WireFormat::WriteEnumToArray("
"$number$, this->$name$(), target);\n");
"target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
" $number$, this->$name$(), target);\n");
}
void EnumFieldGenerator::
GenerateByteSize(io::Printer* printer) const {
printer->Print(variables_,
"total_size += $tag_size$ +\n"
" ::google::protobuf::internal::WireFormat::EnumSize(this->$name$());\n");
" ::google::protobuf::internal::WireFormatLite::EnumSize(this->$name$());\n");
}
// ===================================================================
@ -167,8 +161,7 @@ void RepeatedEnumFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::RepeatedField<int> $name$_;\n");
if (descriptor_->options().packed() &&
descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) {
printer->Print(variables_,
"mutable int _$name$_cached_byte_size_;\n");
}
@ -177,11 +170,11 @@ GeneratePrivateMembers(io::Printer* printer) const {
void RepeatedEnumFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
"inline const ::google::protobuf::RepeatedField<int>& $name$() const;\n"
"inline ::google::protobuf::RepeatedField<int>* mutable_$name$();\n"
"inline $type$ $name$(int index) const;\n"
"inline void set_$name$(int index, $type$ value);\n"
"inline void add_$name$($type$ value);\n");
"inline const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n"
"inline ::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n"
"inline $type$ $name$(int index) const$deprecation$;\n"
"inline void set_$name$(int index, $type$ value)$deprecation$;\n"
"inline void add_$name$($type$ value)$deprecation$;\n");
}
void RepeatedEnumFieldGenerator::
@ -238,7 +231,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
"input->PushLimit(length);\n"
"while (input->BytesUntilLimit() > 0) {\n"
" int value;\n"
" DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));\n"
" DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value));\n"
" if ($type$_IsValid(value)) {\n"
" add_$name$(static_cast< $type$ >(value));\n"
" }\n"
@ -247,11 +240,15 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
} else {
printer->Print(variables_,
"int value;\n"
"DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));\n"
"DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value));\n"
"if ($type$_IsValid(value)) {\n"
" add_$name$(static_cast< $type$ >(value));\n"
"} else {\n"
" mutable_unknown_fields()->AddVarint($number$, value);\n"
" add_$name$(static_cast< $type$ >(value));\n");
if (HasUnknownFields(descriptor_->file())) {
printer->Print(variables_,
"} else {\n"
" mutable_unknown_fields()->AddVarint($number$, value);\n");
}
printer->Print(variables_,
"}\n");
}
}
@ -262,10 +259,10 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
// Write the tag and the size.
printer->Print(variables_,
"if (this->$name$_size() > 0) {\n"
" ::google::protobuf::internal::WireFormat::WriteTag("
"$number$, "
"::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED, "
"output);\n"
" ::google::protobuf::internal::WireFormatLite::WriteTag(\n"
" $number$,\n"
" ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
" output);\n"
" output->WriteVarint32(_$name$_cached_byte_size_);\n"
"}\n");
}
@ -273,12 +270,12 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
"for (int i = 0; i < this->$name$_size(); i++) {\n");
if (descriptor_->options().packed()) {
printer->Print(variables_,
" ::google::protobuf::internal::WireFormat::WriteEnumNoTag("
"this->$name$(i), output);\n");
" ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n"
" this->$name$(i), output);\n");
} else {
printer->Print(variables_,
" ::google::protobuf::internal::WireFormat::WriteEnum("
"$number$, this->$name$(i), output);\n");
" ::google::protobuf::internal::WireFormatLite::WriteEnum(\n"
" $number$, this->$name$(i), output);\n");
}
printer->Print("}\n");
}
@ -289,24 +286,24 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
// Write the tag and the size.
printer->Print(variables_,
"if (this->$name$_size() > 0) {\n"
" target = ::google::protobuf::internal::WireFormat::WriteTagToArray("
"$number$, "
"::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED, "
"target);\n"
" target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n"
" $number$,\n"
" ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
" target);\n"
" target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray("
"_$name$_cached_byte_size_, target);\n"
" _$name$_cached_byte_size_, target);\n"
"}\n");
}
printer->Print(variables_,
"for (int i = 0; i < this->$name$_size(); i++) {\n");
if (descriptor_->options().packed()) {
printer->Print(variables_,
" target = ::google::protobuf::internal::WireFormat::WriteEnumNoTagToArray("
"this->$name$(i), target);\n");
" target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n"
" this->$name$(i), target);\n");
} else {
printer->Print(variables_,
" target = ::google::protobuf::internal::WireFormat::WriteEnumToArray("
"$number$, this->$name$(i), target);\n");
" target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
" $number$, this->$name$(i), target);\n");
}
printer->Print("}\n");
}
@ -319,15 +316,15 @@ GenerateByteSize(io::Printer* printer) const {
printer->Indent();
printer->Print(variables_,
"for (int i = 0; i < this->$name$_size(); i++) {\n"
" data_size += ::google::protobuf::internal::WireFormat::EnumSize(\n"
" data_size += ::google::protobuf::internal::WireFormatLite::EnumSize(\n"
" this->$name$(i));\n"
"}\n");
if (descriptor_->options().packed()) {
printer->Print(variables_,
"if (data_size > 0) {\n"
" total_size += $tag_size$ + "
"::google::protobuf::internal::WireFormat::Int32Size(data_size);\n"
" total_size += $tag_size$ +\n"
" ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
"}\n"
"_$name$_cached_byte_size_ = data_size;\n"
"total_size += data_size;\n");

View File

@ -133,6 +133,7 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) {
vars["global_name"] = global_name;
printer->Print(vars,
"const ::std::string $global_name$_default($default$);\n");
// Update the default to refer to the string global.
vars["default"] = global_name + "_default";
}

View File

@ -33,18 +33,37 @@
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/compiler/cpp/cpp_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
#include <google/protobuf/compiler/cpp/cpp_string_field.h>
#include <google/protobuf/compiler/cpp/cpp_enum_field.h>
#include <google/protobuf/compiler/cpp/cpp_message_field.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
using internal::WireFormat;
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
map<string, string>* variables) {
(*variables)["name"] = FieldName(descriptor);
(*variables)["index"] = SimpleItoa(descriptor->index());
(*variables)["number"] = SimpleItoa(descriptor->number());
(*variables)["classname"] = ClassName(FieldScope(descriptor), false);
(*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
(*variables)["tag_size"] = SimpleItoa(
WireFormat::TagSize(descriptor->number(), descriptor->type()));
(*variables)["deprecation"] = descriptor->options().deprecated()
? " DEPRECATED_PROTOBUF_FIELD" : "";
}
FieldGenerator::~FieldGenerator() {}
FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor)

View File

@ -35,6 +35,9 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
#include <map>
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.h>
@ -49,6 +52,13 @@ namespace protobuf {
namespace compiler {
namespace cpp {
// Helper function: set variables in the map that are the same for all
// field code generators.
// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size',
// 'deprecation'].
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
map<string, string>* variables);
class FieldGenerator {
public:
FieldGenerator() {}

View File

@ -125,13 +125,18 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
// OK, it's now safe to #include other files.
printer->Print(
"#include <google/protobuf/generated_message_reflection.h>\n"
"#include <google/protobuf/generated_message_util.h>\n"
"#include <google/protobuf/repeated_field.h>\n"
"#include <google/protobuf/extension_set.h>\n");
if (file_->service_count() > 0) {
if (HasDescriptorMethods(file_)) {
printer->Print(
"#include <google/protobuf/service.h>\n");
"#include <google/protobuf/generated_message_reflection.h>\n");
if (file_->service_count() > 0) {
printer->Print(
"#include <google/protobuf/service.h>\n");
}
}
for (int i = 0; i < file_->dependency_count(); i++) {
@ -193,19 +198,21 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
printer->Print(kThickSeparator);
printer->Print("\n");
// Generate service definitions.
for (int i = 0; i < file_->service_count(); i++) {
if (i > 0) {
printer->Print("\n");
printer->Print(kThinSeparator);
printer->Print("\n");
if (HasDescriptorMethods(file_)) {
// Generate service definitions.
for (int i = 0; i < file_->service_count(); i++) {
if (i > 0) {
printer->Print("\n");
printer->Print(kThinSeparator);
printer->Print("\n");
}
service_generators_[i]->GenerateDeclarations(printer);
}
service_generators_[i]->GenerateDeclarations(printer);
}
printer->Print("\n");
printer->Print(kThickSeparator);
printer->Print("\n");
printer->Print("\n");
printer->Print(kThickSeparator);
printer->Print("\n");
}
// Declare extension identifiers.
for (int i = 0; i < file_->extension_count(); i++) {
@ -228,6 +235,30 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
// Close up namespace.
GenerateNamespaceClosers(printer);
// Emit GetEnumDescriptor specializations into google::protobuf namespace:
if (HasDescriptorMethods(file_)) {
// The SWIG conditional is to avoid a null-pointer dereference
// (bug 1984964) in swig-1.3.21 resulting from the following syntax:
// namespace X { void Y<Z::W>(); }
// which appears in GetEnumDescriptor() specializations.
printer->Print(
"\n"
"#ifndef SWIG\n"
"namespace google {\nnamespace protobuf {\n"
"\n");
for (int i = 0; i < file_->message_type_count(); i++) {
message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
}
for (int i = 0; i < file_->enum_type_count(); i++) {
enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
}
printer->Print(
"\n"
"} // namespace google\n} // namespace protobuf\n"
"#endif // SWIG\n"
"\n");
}
printer->Print(
"#endif // PROTOBUF_$filename_identifier$__INCLUDED\n",
"filename_identifier", filename_identifier);
@ -237,40 +268,52 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
printer->Print(
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
"\n"
// The generated code calls accessors that might be deprecated. We don't
// want the compiler to warn in generated code.
"#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n"
"#include \"$basename$.pb.h\"\n"
"#include <google/protobuf/stubs/once.h>\n"
"#include <google/protobuf/descriptor.h>\n"
"#include <google/protobuf/io/coded_stream.h>\n"
"#include <google/protobuf/reflection_ops.h>\n"
"#include <google/protobuf/wire_format_inl.h>\n",
"#include <google/protobuf/wire_format_lite_inl.h>\n",
"basename", StripProto(file_->name()));
if (HasDescriptorMethods(file_)) {
printer->Print(
"#include <google/protobuf/descriptor.h>\n"
"#include <google/protobuf/reflection_ops.h>\n"
"#include <google/protobuf/wire_format.h>\n");
}
GenerateNamespaceOpeners(printer);
printer->Print(
"\n"
"namespace {\n"
"\n");
for (int i = 0; i < file_->message_type_count(); i++) {
message_generators_[i]->GenerateDescriptorDeclarations(printer);
}
for (int i = 0; i < file_->enum_type_count(); i++) {
if (HasDescriptorMethods(file_)) {
printer->Print(
"const ::google::protobuf::EnumDescriptor* $name$_descriptor_ = NULL;\n",
"name", ClassName(file_->enum_type(i), false));
}
for (int i = 0; i < file_->service_count(); i++) {
"\n"
"namespace {\n"
"\n");
for (int i = 0; i < file_->message_type_count(); i++) {
message_generators_[i]->GenerateDescriptorDeclarations(printer);
}
for (int i = 0; i < file_->enum_type_count(); i++) {
printer->Print(
"const ::google::protobuf::EnumDescriptor* $name$_descriptor_ = NULL;\n",
"name", ClassName(file_->enum_type(i), false));
}
for (int i = 0; i < file_->service_count(); i++) {
printer->Print(
"const ::google::protobuf::ServiceDescriptor* $name$_descriptor_ = NULL;\n",
"name", file_->service(i)->name());
}
printer->Print(
"const ::google::protobuf::ServiceDescriptor* $name$_descriptor_ = NULL;\n",
"name", file_->service(i)->name());
"\n"
"} // namespace\n"
"\n");
}
printer->Print(
"\n"
"} // namespace\n"
"\n");
// Define our externally-visible BuildDescriptors() function.
// Define our externally-visible BuildDescriptors() function. (For the lite
// library, all this does is initialize default instances.)
GenerateBuildDescriptors(printer);
// Generate enums.
@ -286,12 +329,14 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
message_generators_[i]->GenerateClassMethods(printer);
}
// Generate services.
for (int i = 0; i < file_->service_count(); i++) {
if (i == 0) printer->Print("\n");
printer->Print(kThickSeparator);
printer->Print("\n");
service_generators_[i]->GenerateImplementation(printer);
if (HasDescriptorMethods(file_)) {
// Generate services.
for (int i = 0; i < file_->service_count(); i++) {
if (i == 0) printer->Print("\n");
printer->Print(kThickSeparator);
printer->Print("\n");
service_generators_[i]->GenerateImplementation(printer);
}
}
// Define extensions.
@ -317,79 +362,83 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
// anyone calls descriptor() or GetReflection() on one of the types defined
// in the file.
printer->Print(
"\n"
"void $assigndescriptorsname$() {\n",
"assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
printer->Indent();
// In optimize_for = LITE_RUNTIME mode, we don't generate AssignDescriptors()
// and we only use AddDescriptors() to allocate default instances.
if (HasDescriptorMethods(file_)) {
printer->Print(
"\n"
"void $assigndescriptorsname$() {\n",
"assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
printer->Indent();
// Make sure the file has found its way into the pool. If a descriptor
// is requested *during* static init then AddDescriptors() may not have
// been called yet, so we call it manually. Note that it's fine if
// AddDescriptors() is called multiple times.
printer->Print(
"$adddescriptorsname$();\n",
"adddescriptorsname", GlobalAddDescriptorsName(file_->name()));
// Make sure the file has found its way into the pool. If a descriptor
// is requested *during* static init then AddDescriptors() may not have
// been called yet, so we call it manually. Note that it's fine if
// AddDescriptors() is called multiple times.
printer->Print(
"$adddescriptorsname$();\n",
"adddescriptorsname", GlobalAddDescriptorsName(file_->name()));
// Get the file's descriptor from the pool.
printer->Print(
"const ::google::protobuf::FileDescriptor* file =\n"
" ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(\n"
" \"$filename$\");\n"
// Note that this GOOGLE_CHECK is necessary to prevent a warning about "file"
// being unused when compiling an empty .proto file.
"GOOGLE_CHECK(file != NULL);\n",
"filename", file_->name());
// Get the file's descriptor from the pool.
printer->Print(
"const ::google::protobuf::FileDescriptor* file =\n"
" ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(\n"
" \"$filename$\");\n"
// Note that this GOOGLE_CHECK is necessary to prevent a warning about "file"
// being unused when compiling an empty .proto file.
"GOOGLE_CHECK(file != NULL);\n",
"filename", file_->name());
// Go through all the stuff defined in this file and generated code to
// assign the global descriptor pointers based on the file descriptor.
for (int i = 0; i < file_->message_type_count(); i++) {
message_generators_[i]->GenerateDescriptorInitializer(printer, i);
// Go through all the stuff defined in this file and generated code to
// assign the global descriptor pointers based on the file descriptor.
for (int i = 0; i < file_->message_type_count(); i++) {
message_generators_[i]->GenerateDescriptorInitializer(printer, i);
}
for (int i = 0; i < file_->enum_type_count(); i++) {
enum_generators_[i]->GenerateDescriptorInitializer(printer, i);
}
for (int i = 0; i < file_->service_count(); i++) {
service_generators_[i]->GenerateDescriptorInitializer(printer, i);
}
printer->Outdent();
printer->Print(
"}\n"
"\n");
// ---------------------------------------------------------------
// protobuf_AssignDescriptorsOnce(): The first time it is called, calls
// AssignDescriptors(). All later times, waits for the first call to
// complete and then returns.
printer->Print(
"namespace {\n"
"\n"
"GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);\n"
"inline void protobuf_AssignDescriptorsOnce() {\n"
" ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,\n"
" &$assigndescriptorsname$);\n"
"}\n"
"\n",
"assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
// protobuf_RegisterTypes(): Calls
// MessageFactory::InternalRegisterGeneratedType() for each message type.
printer->Print(
"void protobuf_RegisterTypes(const ::std::string&) {\n"
" protobuf_AssignDescriptorsOnce();\n");
printer->Indent();
for (int i = 0; i < file_->message_type_count(); i++) {
message_generators_[i]->GenerateTypeRegistrations(printer);
}
printer->Outdent();
printer->Print(
"}\n"
"\n"
"} // namespace\n");
}
for (int i = 0; i < file_->enum_type_count(); i++) {
enum_generators_[i]->GenerateDescriptorInitializer(printer, i);
}
for (int i = 0; i < file_->service_count(); i++) {
service_generators_[i]->GenerateDescriptorInitializer(printer, i);
}
printer->Outdent();
printer->Print(
"}\n"
"\n");
// -----------------------------------------------------------------
// protobuf_AssignDescriptorsOnce(): The first time it is called, calls
// AssignDescriptors(). All later times, waits for the first call to
// complete and then returns.
printer->Print(
"namespace {\n"
"\n"
"GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);\n"
"inline void protobuf_AssignDescriptorsOnce() {\n"
" ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,\n"
" &$assigndescriptorsname$);\n"
"}\n"
"\n",
"assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
// protobuf_RegisterTypes(): Calls
// MessageFactory::InternalRegisterGeneratedType() for each message type.
printer->Print(
"void protobuf_RegisterTypes() {\n"
" protobuf_AssignDescriptorsOnce();\n");
printer->Indent();
for (int i = 0; i < file_->message_type_count(); i++) {
message_generators_[i]->GenerateTypeRegistrations(printer);
}
printer->Outdent();
printer->Print(
"}\n"
"\n"
"} // namespace\n");
// -----------------------------------------------------------------
@ -442,32 +491,34 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
"name", GlobalAddDescriptorsName(dependency->name()));
}
// Embed the descriptor. We simply serialize the entire FileDescriptorProto
// and embed it as a string literal, which is parsed and built into real
// descriptors at initialization time.
FileDescriptorProto file_proto;
file_->CopyTo(&file_proto);
string file_data;
file_proto.SerializeToString(&file_data);
if (HasDescriptorMethods(file_)) {
// Embed the descriptor. We simply serialize the entire FileDescriptorProto
// and embed it as a string literal, which is parsed and built into real
// descriptors at initialization time.
FileDescriptorProto file_proto;
file_->CopyTo(&file_proto);
string file_data;
file_proto.SerializeToString(&file_data);
printer->Print(
"::google::protobuf::DescriptorPool::InternalAddGeneratedFile(");
printer->Print(
"::google::protobuf::DescriptorPool::InternalAddGeneratedFile(");
// Only write 40 bytes per line.
static const int kBytesPerLine = 40;
for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
printer->Print("\n \"$data$\"",
"data", CEscape(file_data.substr(i, kBytesPerLine)));
// Only write 40 bytes per line.
static const int kBytesPerLine = 40;
for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
printer->Print("\n \"$data$\"",
"data", CEscape(file_data.substr(i, kBytesPerLine)));
}
printer->Print(
", $size$);\n",
"size", SimpleItoa(file_data.size()));
// Call MessageFactory::InternalRegisterGeneratedFile().
printer->Print(
"::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n"
" \"$filename$\", &protobuf_RegisterTypes);\n",
"filename", file_->name());
}
printer->Print(
", $size$);\n",
"size", SimpleItoa(file_data.size()));
// Call MessageFactory::InternalRegisterGeneratedFile().
printer->Print(
"::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n"
" \"$filename$\", &protobuf_RegisterTypes);\n",
"filename", file_->name());
// Allocate and initialize default instances. This can't be done lazily
// since default instances are returned by simple accessors and are used with

View File

@ -42,39 +42,12 @@
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
namespace {
// Parses a set of comma-delimited name/value pairs, e.g.:
// "foo=bar,baz,qux=corge"
// parses to the pairs:
// ("foo", "bar"), ("baz", ""), ("qux", "corge")
void ParseOptions(const string& text, vector<pair<string, string> >* output) {
vector<string> parts;
SplitStringUsing(text, ",", &parts);
for (int i = 0; i < parts.size(); i++) {
string::size_type equals_pos = parts[i].find_first_of('=');
pair<string, string> value;
if (equals_pos == string::npos) {
value.first = parts[i];
value.second = "";
} else {
value.first = parts[i].substr(0, equals_pos);
value.second = parts[i].substr(equals_pos + 1);
}
output->push_back(value);
}
}
} // namespace
CppGenerator::CppGenerator() {}
CppGenerator::~CppGenerator() {}
@ -83,7 +56,7 @@ bool CppGenerator::Generate(const FileDescriptor* file,
OutputDirectory* output_directory,
string* error) const {
vector<pair<string, string> > options;
ParseOptions(parameter, &options);
ParseGeneratorParameter(parameter, &options);
// -----------------------------------------------------------------
// parse generator options

View File

@ -152,7 +152,18 @@ string FieldName(const FieldDescriptor* field) {
string FieldConstantName(const FieldDescriptor *field) {
string field_name = UnderscoresToCamelCase(field->name(), true);
return "k" + field_name + "FieldNumber";
string result = "k" + field_name + "FieldNumber";
if (!field->is_extension() &&
field->containing_type()->FindFieldByCamelcaseName(
field->camelcase_name()) != field) {
// This field's camelcase name is not unique. As a hack, add the field
// number to the constant name. This makes the constant rather useless,
// but what can we do?
result += "_" + SimpleItoa(field->number());
}
return result;
}
string StripProto(const string& filename) {

View File

@ -37,6 +37,7 @@
#include <string>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
namespace google {
namespace protobuf {
@ -105,6 +106,34 @@ string GlobalAssignDescriptorsName(const string& filename);
// Return the name of the ShutdownFile() function for a given file.
string GlobalShutdownFileName(const string& filename);
// Do message classes in this file keep track of unknown fields?
inline const bool HasUnknownFields(const FileDescriptor *file) {
return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
}
// Does this file have generated parsing, serialization, and other
// standard methods for which reflection-based fallback implementations exist?
inline const bool HasGeneratedMethods(const FileDescriptor *file) {
return file->options().optimize_for() != FileOptions::CODE_SIZE;
}
// Do message classes in this file have descriptor and refelction methods?
inline const bool HasDescriptorMethods(const FileDescriptor *file) {
return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
}
// Should string fields in this file verify that their contents are UTF-8?
inline const bool HasUtf8Verification(const FileDescriptor* file) {
return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
}
// Should we generate a separate, super-optimized code path for serializing to
// flat arrays? We don't do this in Lite mode because we'd rather reduce code
// size.
inline const bool HasFastArraySerialization(const FileDescriptor* file) {
return file->options().optimize_for() == FileOptions::SPEED;
}
} // namespace cpp
} // namespace compiler
} // namespace protobuf

View File

@ -34,14 +34,17 @@
#include <algorithm>
#include <google/protobuf/stubs/hash.h>
#include <map>
#include <vector>
#include <google/protobuf/compiler/cpp/cpp_message.h>
#include <google/protobuf/compiler/cpp/cpp_field.h>
#include <google/protobuf/compiler/cpp/cpp_enum.h>
#include <google/protobuf/compiler/cpp/cpp_extension.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_inl.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/descriptor.pb.h>
namespace google {
@ -50,6 +53,7 @@ namespace compiler {
namespace cpp {
using internal::WireFormat;
using internal::WireFormatLite;
namespace {
@ -195,6 +199,16 @@ GenerateEnumDefinitions(io::Printer* printer) {
}
}
void MessageGenerator::
GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
nested_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
}
for (int i = 0; i < descriptor_->enum_type_count(); i++) {
enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
}
}
void MessageGenerator::
GenerateFieldAccessorDeclarations(io::Printer* printer) {
for (int i = 0; i < descriptor_->field_count(); i++) {
@ -203,17 +217,16 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
PrintFieldComment(printer, field);
map<string, string> vars;
vars["name"] = FieldName(field);
SetCommonFieldVariables(field, &vars);
vars["constant_name"] = FieldConstantName(field);
vars["number"] = SimpleItoa(field->number());
if (field->is_repeated()) {
printer->Print(vars, "inline int $name$_size() const;\n");
printer->Print(vars, "inline int $name$_size() const$deprecation$;\n");
} else {
printer->Print(vars, "inline bool has_$name$() const;\n");
printer->Print(vars, "inline bool has_$name$() const$deprecation$;\n");
}
printer->Print(vars, "inline void clear_$name$();\n");
printer->Print(vars, "inline void clear_$name$()$deprecation$;\n");
printer->Print(vars, "static const int $constant_name$ = $number$;\n");
// Generate type-specific accessor declarations.
@ -241,9 +254,7 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) {
PrintFieldComment(printer, field);
map<string, string> vars;
vars["name"] = FieldName(field);
vars["index"] = SimpleItoa(field->index());
vars["classname"] = classname_;
SetCommonFieldVariables(field, &vars);
// Generate has_$name$() or $name$_size().
if (field->is_repeated()) {
@ -297,9 +308,11 @@ GenerateClassDefinition(io::Printer* printer) {
} else {
vars["dllexport"] = dllexport_decl_ + " ";
}
vars["superclass"] = HasDescriptorMethods(descriptor_->file()) ?
"Message" : "MessageLite";
printer->Print(vars,
"class $dllexport$$classname$ : public ::google::protobuf::Message {\n"
"class $dllexport$$classname$ : public ::google::protobuf::$superclass$ {\n"
" public:\n");
printer->Indent();
@ -313,16 +326,28 @@ GenerateClassDefinition(io::Printer* printer) {
" CopyFrom(from);\n"
" return *this;\n"
"}\n"
"\n"
"inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {\n"
" return _unknown_fields_;\n"
"}\n"
"\n"
"inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {\n"
" return &_unknown_fields_;\n"
"}\n"
"\n"
"static const ::google::protobuf::Descriptor* descriptor();\n"
"\n");
if (HasUnknownFields(descriptor_->file())) {
printer->Print(
"inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {\n"
" return _unknown_fields_;\n"
"}\n"
"\n"
"inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {\n"
" return &_unknown_fields_;\n"
"}\n"
"\n");
}
// Only generate this member if it's not disabled.
if (HasDescriptorMethods(descriptor_->file()) &&
!descriptor_->options().no_standard_descriptor_accessor()) {
printer->Print(vars,
"static const ::google::protobuf::Descriptor* descriptor();\n");
}
printer->Print(vars,
"static const $classname$& default_instance();\n"
"void Swap($classname$* other);\n"
"\n"
@ -330,28 +355,29 @@ GenerateClassDefinition(io::Printer* printer) {
"\n"
"$classname$* New() const;\n");
if (descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
if (HasGeneratedMethods(descriptor_->file())) {
if (HasDescriptorMethods(descriptor_->file())) {
printer->Print(vars,
"void CopyFrom(const ::google::protobuf::Message& from);\n"
"void MergeFrom(const ::google::protobuf::Message& from);\n");
} else {
printer->Print(vars,
"void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);\n");
}
printer->Print(vars,
"void CopyFrom(const ::google::protobuf::Message& from);\n"
"void MergeFrom(const ::google::protobuf::Message& from);\n"
"void CopyFrom(const $classname$& from);\n"
"void MergeFrom(const $classname$& from);\n"
"void Clear();\n"
"bool IsInitialized() const;\n");
if (!descriptor_->options().message_set_wire_format()) {
// For message_set_wire_format, we don't generate parsing or
// serialization code even if optimize_for = SPEED, since MessageSet
// encoding is somewhat more complicated than normal extension encoding
// and we'd like to avoid having to implement it in multiple places.
// WireFormat's implementation is probably good enough.
printer->Print(vars,
"\n"
"int ByteSize() const;\n"
"bool MergePartialFromCodedStream(\n"
" ::google::protobuf::io::CodedInputStream* input);\n"
"void SerializeWithCachedSizes(\n"
" ::google::protobuf::io::CodedOutputStream* output) const;\n"
"bool IsInitialized() const;\n"
"\n"
"int ByteSize() const;\n"
"bool MergePartialFromCodedStream(\n"
" ::google::protobuf::io::CodedInputStream* input);\n"
"void SerializeWithCachedSizes(\n"
" ::google::protobuf::io::CodedOutputStream* output) const;\n");
if (HasFastArraySerialization(descriptor_->file())) {
printer->Print(
"::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;\n");
}
}
@ -363,10 +389,19 @@ GenerateClassDefinition(io::Printer* printer) {
"void SharedDtor();\n"
"void SetCachedSize(int size) const { _cached_size_ = size; }\n"
"public:\n"
"\n"
"const ::google::protobuf::Descriptor* GetDescriptor() const;\n"
"const ::google::protobuf::Reflection* GetReflection() const;\n"
"\n"
"\n");
if (HasDescriptorMethods(descriptor_->file())) {
printer->Print(
"::google::protobuf::Metadata GetMetadata() const;\n"
"\n");
} else {
printer->Print(
"::std::string GetTypeName() const;\n"
"\n");
}
printer->Print(
"// nested types ----------------------------------------------------\n"
"\n");
@ -411,9 +446,13 @@ GenerateClassDefinition(io::Printer* printer) {
"::google::protobuf::internal::ExtensionSet _extensions_;\n");
}
if (HasUnknownFields(descriptor_->file())) {
printer->Print(
"::google::protobuf::UnknownFieldSet _unknown_fields_;\n");
}
// TODO(kenton): Make _cached_size_ an atomic<int> when C++ supports it.
printer->Print(
"::google::protobuf::UnknownFieldSet _unknown_fields_;\n"
"mutable int _cached_size_;\n"
"\n");
for (int i = 0; i < descriptor_->field_count(); i++) {
@ -431,7 +470,8 @@ GenerateClassDefinition(io::Printer* printer) {
GlobalAddDescriptorsName(descriptor_->file()->name()));
printer->Print(
"friend void $assigndescriptorsname$();\n"
"friend void $shutdownfilename$();\n",
"friend void $shutdownfilename$();\n"
"\n",
"assigndescriptorsname",
GlobalAssignDescriptorsName(descriptor_->file()->name()),
"shutdownfilename", GlobalShutdownFileName(descriptor_->file()->name()));
@ -605,10 +645,15 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) {
void MessageGenerator::
GenerateShutdownCode(io::Printer* printer) {
printer->Print(
"delete $classname$::default_instance_;\n"
"delete $classname$_reflection_;\n",
"delete $classname$::default_instance_;\n",
"classname", classname_);
if (HasDescriptorMethods(descriptor_->file())) {
printer->Print(
"delete $classname$_reflection_;\n",
"classname", classname_);
}
// Handle nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
nested_generators_[i]->GenerateShutdownCode(printer);
@ -655,29 +700,24 @@ GenerateClassMethods(io::Printer* printer) {
GenerateStructors(printer);
printer->Print("\n");
if (descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
if (HasGeneratedMethods(descriptor_->file())) {
GenerateClear(printer);
printer->Print("\n");
if (!descriptor_->options().message_set_wire_format()) {
// For message_set_wire_format, we don't generate parsing or
// serialization code even if optimize_for = SPEED, since MessageSet
// encoding is somewhat more complicated than normal extension encoding
// and we'd like to avoid having to implement it in multiple places.
// WireFormat's implementation is probably good enough.
GenerateMergeFromCodedStream(printer);
printer->Print("\n");
GenerateMergeFromCodedStream(printer);
printer->Print("\n");
GenerateSerializeWithCachedSizes(printer);
printer->Print("\n");
GenerateSerializeWithCachedSizes(printer);
printer->Print("\n");
if (HasFastArraySerialization(descriptor_->file())) {
GenerateSerializeWithCachedSizesToArray(printer);
printer->Print("\n");
GenerateByteSize(printer);
printer->Print("\n");
}
GenerateByteSize(printer);
printer->Print("\n");
GenerateMergeFrom(printer);
printer->Print("\n");
@ -691,16 +731,26 @@ GenerateClassMethods(io::Printer* printer) {
GenerateSwap(printer);
printer->Print("\n");
printer->Print(
"const ::google::protobuf::Descriptor* $classname$::GetDescriptor() const {\n"
" return descriptor();\n"
"}\n"
"\n"
"const ::google::protobuf::Reflection* $classname$::GetReflection() const {\n"
" protobuf_AssignDescriptorsOnce();\n"
" return $classname$_reflection_;\n"
"}\n",
"classname", classname_);
if (HasDescriptorMethods(descriptor_->file())) {
printer->Print(
"::google::protobuf::Metadata $classname$::GetMetadata() const {\n"
" protobuf_AssignDescriptorsOnce();\n"
" ::google::protobuf::Metadata metadata;\n"
" metadata.descriptor = $classname$_descriptor_;\n"
" metadata.reflection = $classname$_reflection_;\n"
" return metadata;\n"
"}\n"
"\n",
"classname", classname_);
} else {
printer->Print(
"::std::string $classname$::GetTypeName() const {\n"
" return \"$type_name$\";\n"
"}\n"
"\n",
"classname", classname_,
"type_name", descriptor_->full_name());
}
}
void MessageGenerator::
@ -723,18 +773,6 @@ GenerateOffsets(io::Printer* printer) {
printer->Print("};\n");
}
void MessageGenerator::
GenerateInitializerList(io::Printer* printer) {
printer->Indent();
printer->Indent();
printer->Print(
"::google::protobuf::Message()");
printer->Outdent();
printer->Outdent();
}
void MessageGenerator::
GenerateSharedConstructorCode(io::Printer* printer) {
printer->Print(
@ -797,17 +835,14 @@ void MessageGenerator::
GenerateStructors(io::Printer* printer) {
// Generate the default constructor.
printer->Print(
"$classname$::$classname$()\n"
" : ",
"classname", classname_);
GenerateInitializerList(printer);
printer->Print(" {\n"
"$classname$::$classname$() {\n"
" SharedCtor();\n"
"}\n");
"}\n",
"classname", classname_);
printer->Print(
"\n"
"void $classname$::InitAsDefaultInstance() {",
"void $classname$::InitAsDefaultInstance() {\n",
"classname", classname_);
// The default instance needs all of its embedded message pointers
@ -833,15 +868,12 @@ GenerateStructors(io::Printer* printer) {
// Generate the copy constructor.
printer->Print(
"$classname$::$classname$(const $classname$& from)\n"
" : ",
"classname", classname_);
GenerateInitializerList(printer);
printer->Print(" {\n"
"$classname$::$classname$(const $classname$& from) {\n"
" SharedCtor();\n"
" MergeFrom(from);\n"
"}\n"
"\n");
"\n",
"classname", classname_);
// Generate the shared constructor code.
GenerateSharedConstructorCode(printer);
@ -857,12 +889,21 @@ GenerateStructors(io::Printer* printer) {
// Generate the shared destructor code.
GenerateSharedDestructorCode(printer);
// Only generate this member if it's not disabled.
if (HasDescriptorMethods(descriptor_->file()) &&
!descriptor_->options().no_standard_descriptor_accessor()) {
printer->Print(
"const ::google::protobuf::Descriptor* $classname$::descriptor() {\n"
" protobuf_AssignDescriptorsOnce();\n"
" return $classname$_descriptor_;\n"
"}\n"
"\n",
"classname", classname_,
"adddescriptorsname",
GlobalAddDescriptorsName(descriptor_->file()->name()));
}
printer->Print(
"const ::google::protobuf::Descriptor* $classname$::descriptor() {\n"
" protobuf_AssignDescriptorsOnce();\n"
" return $classname$_descriptor_;\n"
"}\n"
"\n"
"const $classname$& $classname$::default_instance() {\n"
" if (default_instance_ == NULL) $adddescriptorsname$();"
" return *default_instance_;\n"
@ -951,8 +992,12 @@ GenerateClear(io::Printer* printer) {
}
printer->Print(
"::memset(_has_bits_, 0, sizeof(_has_bits_));\n"
"mutable_unknown_fields()->Clear();\n");
"::memset(_has_bits_, 0, sizeof(_has_bits_));\n");
if (HasUnknownFields(descriptor_->file())) {
printer->Print(
"mutable_unknown_fields()->Clear();\n");
}
printer->Outdent();
printer->Print("}\n");
@ -967,7 +1012,7 @@ GenerateSwap(io::Printer* printer) {
printer->Print("if (other != this) {\n");
printer->Indent();
if ( descriptor_->file()->options().optimize_for() == FileOptions::SPEED ) {
if (HasGeneratedMethods(descriptor_->file())) {
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
field_generators_.get(field).GenerateSwappingCode(printer);
@ -978,7 +1023,9 @@ GenerateSwap(io::Printer* printer) {
"i", SimpleItoa(i));
}
printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n");
if (HasUnknownFields(descriptor_->file())) {
printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n");
}
printer->Print("std::swap(_cached_size_, other->_cached_size_);\n");
if (descriptor_->extension_range_count() > 0) {
printer->Print("_extensions_.Swap(&other->_extensions_);\n");
@ -987,7 +1034,6 @@ GenerateSwap(io::Printer* printer) {
printer->Print("GetReflection()->Swap(this, other);");
}
printer->Outdent();
printer->Print("}\n");
printer->Outdent();
@ -996,31 +1042,42 @@ GenerateSwap(io::Printer* printer) {
void MessageGenerator::
GenerateMergeFrom(io::Printer* printer) {
// Generate the generalized MergeFrom (aka that which takes in the Message
// base class as a parameter).
printer->Print(
"void $classname$::MergeFrom(const ::google::protobuf::Message& from) {\n"
" GOOGLE_CHECK_NE(&from, this);\n",
"classname", classname_);
printer->Indent();
if (HasDescriptorMethods(descriptor_->file())) {
// Generate the generalized MergeFrom (aka that which takes in the Message
// base class as a parameter).
printer->Print(
"void $classname$::MergeFrom(const ::google::protobuf::Message& from) {\n"
" GOOGLE_CHECK_NE(&from, this);\n",
"classname", classname_);
printer->Indent();
// Cast the message to the proper type. If we find that the message is
// *not* of the proper type, we can still call Merge via the reflection
// system, as the GOOGLE_CHECK above ensured that we have the same descriptor
// for each message.
printer->Print(
"const $classname$* source =\n"
" ::google::protobuf::internal::dynamic_cast_if_available<const $classname$*>(\n"
" &from);\n"
"if (source == NULL) {\n"
" ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n"
"} else {\n"
" MergeFrom(*source);\n"
"}\n",
"classname", classname_);
// Cast the message to the proper type. If we find that the message is
// *not* of the proper type, we can still call Merge via the reflection
// system, as the GOOGLE_CHECK above ensured that we have the same descriptor
// for each message.
printer->Print(
"const $classname$* source =\n"
" ::google::protobuf::internal::dynamic_cast_if_available<const $classname$*>(\n"
" &from);\n"
"if (source == NULL) {\n"
" ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n"
"} else {\n"
" MergeFrom(*source);\n"
"}\n",
"classname", classname_);
printer->Outdent();
printer->Print("}\n\n");
printer->Outdent();
printer->Print("}\n\n");
} else {
// Generate CheckTypeAndMergeFrom().
printer->Print(
"void $classname$::CheckTypeAndMergeFrom(\n"
" const ::google::protobuf::MessageLite& from) {\n"
" MergeFrom(*::google::protobuf::down_cast<const $classname$*>(&from));\n"
"}\n"
"\n",
"classname", classname_);
}
// Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast.
printer->Print(
@ -1082,8 +1139,10 @@ GenerateMergeFrom(io::Printer* printer) {
printer->Print("_extensions_.MergeFrom(from._extensions_);\n");
}
printer->Print(
"mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n");
if (HasUnknownFields(descriptor_->file())) {
printer->Print(
"mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n");
}
printer->Outdent();
printer->Print("}\n");
@ -1091,20 +1150,22 @@ GenerateMergeFrom(io::Printer* printer) {
void MessageGenerator::
GenerateCopyFrom(io::Printer* printer) {
// Generate the generalized CopyFrom (aka that which takes in the Message
// base class as a parameter).
printer->Print(
"void $classname$::CopyFrom(const ::google::protobuf::Message& from) {\n",
"classname", classname_);
printer->Indent();
if (HasDescriptorMethods(descriptor_->file())) {
// Generate the generalized CopyFrom (aka that which takes in the Message
// base class as a parameter).
printer->Print(
"void $classname$::CopyFrom(const ::google::protobuf::Message& from) {\n",
"classname", classname_);
printer->Indent();
printer->Print(
"if (&from == this) return;\n"
"Clear();\n"
"MergeFrom(from);\n");
printer->Print(
"if (&from == this) return;\n"
"Clear();\n"
"MergeFrom(from);\n");
printer->Outdent();
printer->Print("}\n\n");
printer->Outdent();
printer->Print("}\n\n");
}
// Generate the class-specific CopyFrom.
printer->Print(
@ -1123,6 +1184,18 @@ GenerateCopyFrom(io::Printer* printer) {
void MessageGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) {
if (descriptor_->options().message_set_wire_format()) {
// Special-case MessageSet.
printer->Print(
"bool $classname$::MergePartialFromCodedStream(\n"
" ::google::protobuf::io::CodedInputStream* input) {\n"
" return _extensions_.ParseMessageSet(input, default_instance_,\n"
" mutable_unknown_fields());\n"
"}\n",
"classname", classname_);
return;
}
printer->Print(
"bool $classname$::MergePartialFromCodedStream(\n"
" ::google::protobuf::io::CodedInputStream* input) {\n"
@ -1144,7 +1217,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
// creates a jump table that is 8x larger and sparser, and meanwhile the
// if()s are highly predictable.
printer->Print(
"switch (::google::protobuf::internal::WireFormat::GetTagFieldNumber(tag)) {\n");
"switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {\n");
printer->Indent();
@ -1158,8 +1231,8 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Print(
"case $number$: {\n"
" if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=\n"
" ::google::protobuf::internal::WireFormat::WIRETYPE_$wiretype$) {\n"
" if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) !=\n"
" ::google::protobuf::internal::WireFormatLite::WIRETYPE_$wiretype$) {\n"
" goto handle_uninterpreted;\n"
" }\n",
"number", SimpleItoa(field->number()),
@ -1214,8 +1287,8 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
// Is this an end-group tag? If so, this must be the end of the message.
printer->Print(
"if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) ==\n"
" ::google::protobuf::internal::WireFormat::WIRETYPE_END_GROUP) {\n"
"if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n"
" ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {\n"
" return true;\n"
"}\n");
@ -1228,10 +1301,10 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
descriptor_->extension_range(i);
if (i > 0) printer->Print(" ||\n ");
uint32 start_tag = WireFormat::MakeTag(
range->start, static_cast<WireFormat::WireType>(0));
uint32 end_tag = WireFormat::MakeTag(
range->end, static_cast<WireFormat::WireType>(0));
uint32 start_tag = WireFormatLite::MakeTag(
range->start, static_cast<WireFormatLite::WireType>(0));
uint32 end_tag = WireFormatLite::MakeTag(
range->end, static_cast<WireFormatLite::WireType>(0));
if (range->end > FieldDescriptor::kMaxNumber) {
printer->Print(
@ -1244,17 +1317,29 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
"end", SimpleItoa(end_tag));
}
}
printer->Print(") {\n"
" DO_(_extensions_.ParseField(tag, input, default_instance_,\n"
" mutable_unknown_fields()));\n"
printer->Print(") {\n");
if (HasUnknownFields(descriptor_->file())) {
printer->Print(
" DO_(_extensions_.ParseField(tag, input, default_instance_,\n"
" mutable_unknown_fields()));\n");
} else {
printer->Print(
" DO_(_extensions_.ParseField(tag, input, default_instance_));\n");
}
printer->Print(
" continue;\n"
"}\n");
}
// We really don't recognize this tag. Skip it.
printer->Print(
"DO_(::google::protobuf::internal::WireFormat::SkipField(\n"
" input, tag, mutable_unknown_fields()));\n");
if (HasUnknownFields(descriptor_->file())) {
printer->Print(
"DO_(::google::protobuf::internal::WireFormat::SkipField(\n"
" input, tag, mutable_unknown_fields()));\n");
} else {
printer->Print(
"DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));\n");
}
if (descriptor_->field_count() > 0) {
printer->Print("break;\n");
@ -1319,21 +1404,41 @@ void MessageGenerator::GenerateSerializeOneExtensionRange(
void MessageGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) {
if (descriptor_->options().message_set_wire_format()) {
// Special-case MessageSet.
printer->Print(
"void $classname$::SerializeWithCachedSizes(\n"
" ::google::protobuf::io::CodedOutputStream* output) const {\n"
" _extensions_.SerializeMessageSetWithCachedSizes(output);\n",
"classname", classname_);
if (HasUnknownFields(descriptor_->file())) {
printer->Print(
" ::google::protobuf::internal::WireFormat::SerializeUnknownMessageSetItems(\n"
" unknown_fields(), output);\n");
}
printer->Print(
"}\n");
return;
}
printer->Print(
"void $classname$::SerializeWithCachedSizes(\n"
" ::google::protobuf::io::CodedOutputStream* output) const {\n",
"classname", classname_);
printer->Indent();
printer->Print(
"::google::protobuf::uint8* raw_buffer = "
"output->GetDirectBufferForNBytesAndAdvance(_cached_size_);\n"
"if (raw_buffer != NULL) {\n"
" $classname$::SerializeWithCachedSizesToArray(raw_buffer);\n"
" return;\n"
"}\n"
"\n",
"classname", classname_);
if (HasFastArraySerialization(descriptor_->file())) {
printer->Print(
"::google::protobuf::uint8* raw_buffer = "
"output->GetDirectBufferForNBytesAndAdvance(_cached_size_);\n"
"if (raw_buffer != NULL) {\n"
" $classname$::SerializeWithCachedSizesToArray(raw_buffer);\n"
" return;\n"
"}\n"
"\n",
"classname", classname_);
}
GenerateSerializeWithCachedSizesBody(printer, false);
printer->Outdent();
@ -1343,6 +1448,26 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) {
void MessageGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) {
if (descriptor_->options().message_set_wire_format()) {
// Special-case MessageSet.
printer->Print(
"::google::protobuf::uint8* $classname$::SerializeWithCachedSizesToArray(\n"
" ::google::protobuf::uint8* target) const {\n"
" target =\n"
" _extensions_.SerializeMessageSetWithCachedSizesToArray(target);\n",
"classname", classname_);
if (HasUnknownFields(descriptor_->file())) {
printer->Print(
" target = ::google::protobuf::internal::WireFormat::\n"
" SerializeUnknownMessageSetItemsToArray(\n"
" unknown_fields(), target);\n");
}
printer->Print(
" return target;\n"
"}\n");
return;
}
printer->Print(
"::google::protobuf::uint8* $classname$::SerializeWithCachedSizesToArray(\n"
" ::google::protobuf::uint8* target) const {\n",
@ -1389,26 +1514,46 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
}
}
printer->Print("if (!unknown_fields().empty()) {\n");
printer->Indent();
if (to_array) {
printer->Print(
"target = "
"::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n"
" unknown_fields(), target);\n");
} else {
printer->Print(
"::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n"
" unknown_fields(), output);\n");
}
printer->Outdent();
if (HasUnknownFields(descriptor_->file())) {
printer->Print("if (!unknown_fields().empty()) {\n");
printer->Indent();
if (to_array) {
printer->Print(
"target = "
"::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n"
" unknown_fields(), target);\n");
} else {
printer->Print(
"::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n"
" unknown_fields(), output);\n");
}
printer->Outdent();
printer->Print(
"}\n");
printer->Print(
"}\n");
}
}
void MessageGenerator::
GenerateByteSize(io::Printer* printer) {
if (descriptor_->options().message_set_wire_format()) {
// Special-case MessageSet.
printer->Print(
"int $classname$::ByteSize() const {\n"
" int total_size = _extensions_.MessageSetByteSize();\n",
"classname", classname_);
if (HasUnknownFields(descriptor_->file())) {
printer->Print(
" total_size += ::google::protobuf::internal::WireFormat::\n"
" ComputeUnknownMessageSetItemsSize(unknown_fields());\n");
}
printer->Print(
" _cached_size_ = total_size;\n"
" return total_size;\n"
"}\n");
return;
}
printer->Print(
"int $classname$::ByteSize() const {\n",
"classname", classname_);
@ -1478,14 +1623,16 @@ GenerateByteSize(io::Printer* printer) {
"\n");
}
printer->Print("if (!unknown_fields().empty()) {\n");
printer->Indent();
printer->Print(
"total_size +=\n"
" ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n"
" unknown_fields());\n");
printer->Outdent();
printer->Print("}\n");
if (HasUnknownFields(descriptor_->file())) {
printer->Print("if (!unknown_fields().empty()) {\n");
printer->Indent();
printer->Print(
"total_size +=\n"
" ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n"
" unknown_fields());\n");
printer->Outdent();
printer->Print("}\n");
}
// We update _cached_size_ even though this is a const method. In theory,
// this is not thread-compatible, because concurrent writes have undefined

View File

@ -69,6 +69,10 @@ class MessageGenerator {
// definitions because those classes use the enums definitions).
void GenerateEnumDefinitions(io::Printer* printer);
// Generate specializations of GetEnumDescriptor<MyEnum>().
// Precondition: in ::google::protobuf namespace.
void GenerateGetEnumDescriptorSpecializations(io::Printer* printer);
// Generate definitions for this class and all its nested types.
void GenerateClassDefinition(io::Printer* printer);
@ -125,11 +129,6 @@ class MessageGenerator {
// Generate the shared destructor code.
void GenerateSharedDestructorCode(io::Printer* printer);
// Generate the member initializer list for the constructors. The member
// initializer list is shared between the default constructor and the copy
// constructor.
void GenerateInitializerList(io::Printer* printer);
// Generate standard Message methods.
void GenerateClear(io::Printer* printer);
void GenerateMergeFromCodedStream(io::Printer* printer);

View File

@ -35,7 +35,6 @@
#include <google/protobuf/compiler/cpp/cpp_message_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format_inl.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
@ -43,22 +42,12 @@ namespace protobuf {
namespace compiler {
namespace cpp {
using internal::WireFormat;
namespace {
// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
// repeat code between this and the other field types.
void SetMessageVariables(const FieldDescriptor* descriptor,
map<string, string>* variables) {
(*variables)["name"] = FieldName(descriptor);
SetCommonFieldVariables(descriptor, variables);
(*variables)["type"] = ClassName(descriptor->message_type(), true);
(*variables)["index"] = SimpleItoa(descriptor->index());
(*variables)["number"] = SimpleItoa(descriptor->number());
(*variables)["classname"] = ClassName(FieldScope(descriptor), false);
(*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
(*variables)["tag_size"] = SimpleItoa(
WireFormat::TagSize(descriptor->number(), descriptor->type()));
}
} // namespace
@ -81,8 +70,8 @@ GeneratePrivateMembers(io::Printer* printer) const {
void MessageFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
"inline const $type$& $name$() const;\n"
"inline $type$* mutable_$name$();\n");
"inline const $type$& $name$() const$deprecation$;\n"
"inline $type$* mutable_$name$()$deprecation$;\n");
}
void MessageFieldGenerator::
@ -124,35 +113,35 @@ void MessageFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(\n"
"DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
" input, mutable_$name$()));\n");
} else {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormat::ReadGroupNoVirtual("
"$number$, input, mutable_$name$()));\n");
"DO_(::google::protobuf::internal::WireFormatLite::ReadGroupNoVirtual(\n"
" $number$, input, mutable_$name$()));\n");
}
}
void MessageFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual("
"$number$, this->$name$(), output);\n");
"::google::protobuf::internal::WireFormatLite::Write$declared_type$NoVirtual(\n"
" $number$, this->$name$(), output);\n");
}
void MessageFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
printer->Print(variables_,
"target = ::google::protobuf::internal::WireFormat::"
"Write$declared_type$NoVirtualToArray("
"$number$, this->$name$(), target);\n");
"target = ::google::protobuf::internal::WireFormatLite::\n"
" Write$declared_type$NoVirtualToArray(\n"
" $number$, this->$name$(), target);\n");
}
void MessageFieldGenerator::
GenerateByteSize(io::Printer* printer) const {
printer->Print(variables_,
"total_size += $tag_size$ +\n"
" ::google::protobuf::internal::WireFormat::$declared_type$SizeNoVirtual(\n"
" ::google::protobuf::internal::WireFormatLite::$declared_type$SizeNoVirtual(\n"
" this->$name$());\n");
}
@ -175,11 +164,13 @@ GeneratePrivateMembers(io::Printer* printer) const {
void RepeatedMessageFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
"inline const ::google::protobuf::RepeatedPtrField< $type$ >& $name$() const;\n"
"inline ::google::protobuf::RepeatedPtrField< $type$ >* mutable_$name$();\n"
"inline const $type$& $name$(int index) const;\n"
"inline $type$* mutable_$name$(int index);\n"
"inline $type$* add_$name$();\n");
"inline const ::google::protobuf::RepeatedPtrField< $type$ >& $name$() const"
"$deprecation$;\n"
"inline ::google::protobuf::RepeatedPtrField< $type$ >* mutable_$name$()"
"$deprecation$;\n"
"inline const $type$& $name$(int index) const$deprecation$;\n"
"inline $type$* mutable_$name$(int index)$deprecation$;\n"
"inline $type$* add_$name$()$deprecation$;\n");
}
void RepeatedMessageFieldGenerator::
@ -228,12 +219,12 @@ void RepeatedMessageFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormat::ReadMessageNoVirtual(\n"
" input, add_$name$()));\n");
"DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
" input, add_$name$()));\n");
} else {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormat::ReadGroupNoVirtual("
"$number$, input, add_$name$()));\n");
"DO_(::google::protobuf::internal::WireFormatLite::ReadGroupNoVirtual(\n"
" $number$, input, add_$name$()));\n");
}
}
@ -241,8 +232,8 @@ void RepeatedMessageFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
printer->Print(variables_,
"for (int i = 0; i < this->$name$_size(); i++) {\n"
" ::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual("
"$number$, this->$name$(i), output);\n"
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoVirtual(\n"
" $number$, this->$name$(i), output);\n"
"}\n");
}
@ -250,9 +241,9 @@ void RepeatedMessageFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
printer->Print(variables_,
"for (int i = 0; i < this->$name$_size(); i++) {\n"
" target = ::google::protobuf::internal::WireFormat::"
"Write$declared_type$NoVirtualToArray("
"$number$, this->$name$(i), target);\n"
" target = ::google::protobuf::internal::WireFormatLite::\n"
" Write$declared_type$NoVirtualToArray(\n"
" $number$, this->$name$(i), target);\n"
"}\n");
}
@ -262,7 +253,7 @@ GenerateByteSize(io::Printer* printer) const {
"total_size += $tag_size$ * this->$name$_size();\n"
"for (int i = 0; i < this->$name$_size(); i++) {\n"
" total_size +=\n"
" ::google::protobuf::internal::WireFormat::$declared_type$SizeNoVirtual(\n"
" ::google::protobuf::internal::WireFormatLite::$declared_type$SizeNoVirtual(\n"
" this->$name$(i));\n"
"}\n");
}

View File

@ -35,7 +35,7 @@
#include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format_inl.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
@ -43,7 +43,7 @@ namespace protobuf {
namespace compiler {
namespace cpp {
using internal::WireFormat;
using internal::WireFormatLite;
namespace {
@ -57,14 +57,14 @@ int FixedSize(FieldDescriptor::Type type) {
case FieldDescriptor::TYPE_UINT64 : return -1;
case FieldDescriptor::TYPE_SINT32 : return -1;
case FieldDescriptor::TYPE_SINT64 : return -1;
case FieldDescriptor::TYPE_FIXED32 : return WireFormat::kFixed32Size;
case FieldDescriptor::TYPE_FIXED64 : return WireFormat::kFixed64Size;
case FieldDescriptor::TYPE_SFIXED32: return WireFormat::kSFixed32Size;
case FieldDescriptor::TYPE_SFIXED64: return WireFormat::kSFixed64Size;
case FieldDescriptor::TYPE_FLOAT : return WireFormat::kFloatSize;
case FieldDescriptor::TYPE_DOUBLE : return WireFormat::kDoubleSize;
case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size;
case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size;
case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size;
case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size;
case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize;
case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize;
case FieldDescriptor::TYPE_BOOL : return WireFormat::kBoolSize;
case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize;
case FieldDescriptor::TYPE_ENUM : return -1;
case FieldDescriptor::TYPE_STRING : return -1;
@ -79,20 +79,11 @@ int FixedSize(FieldDescriptor::Type type) {
return -1;
}
// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
// repeat code between this and the other field types.
void SetPrimitiveVariables(const FieldDescriptor* descriptor,
map<string, string>* variables) {
(*variables)["name"] = FieldName(descriptor);
SetCommonFieldVariables(descriptor, variables);
(*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type());
(*variables)["default"] = DefaultValue(descriptor);
(*variables)["index"] = SimpleItoa(descriptor->index());
(*variables)["number"] = SimpleItoa(descriptor->number());
(*variables)["classname"] = ClassName(FieldScope(descriptor), false);
(*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
(*variables)["tag_size"] = SimpleItoa(
WireFormat::TagSize(descriptor->number(), descriptor->type()));
int fixed_size = FixedSize(descriptor->type());
if (fixed_size != -1) {
(*variables)["fixed_size"] = SimpleItoa(fixed_size);
@ -119,8 +110,8 @@ GeneratePrivateMembers(io::Printer* printer) const {
void PrimitiveFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
"inline $type$ $name$() const;\n"
"inline void set_$name$($type$ value);\n");
"inline $type$ $name$() const$deprecation$;\n"
"inline void set_$name$($type$ value)$deprecation$;\n");
}
void PrimitiveFieldGenerator::
@ -158,7 +149,7 @@ GenerateConstructorCode(io::Printer* printer) const {
void PrimitiveFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormat::Read$declared_type$(\n"
"DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
" input, &$name$_));\n"
"_set_bit($index$);\n");
}
@ -166,14 +157,14 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
void PrimitiveFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::internal::WireFormat::Write$declared_type$("
"::google::protobuf::internal::WireFormatLite::Write$declared_type$("
"$number$, this->$name$(), output);\n");
}
void PrimitiveFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
printer->Print(variables_,
"target = ::google::protobuf::internal::WireFormat::Write$declared_type$ToArray("
"target = ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray("
"$number$, this->$name$(), target);\n");
}
@ -183,7 +174,7 @@ GenerateByteSize(io::Printer* printer) const {
if (fixed_size == -1) {
printer->Print(variables_,
"total_size += $tag_size$ +\n"
" ::google::protobuf::internal::WireFormat::$declared_type$Size(\n"
" ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
" this->$name$());\n");
} else {
printer->Print(variables_,
@ -205,8 +196,7 @@ void RepeatedPrimitiveFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::RepeatedField< $type$ > $name$_;\n");
if (descriptor_->options().packed() &&
descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) {
printer->Print(variables_,
"mutable int _$name$_cached_byte_size_;\n");
}
@ -215,11 +205,12 @@ GeneratePrivateMembers(io::Printer* printer) const {
void RepeatedPrimitiveFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
"inline const ::google::protobuf::RepeatedField< $type$ >& $name$() const;\n"
"inline ::google::protobuf::RepeatedField< $type$ >* mutable_$name$();\n"
"inline $type$ $name$(int index) const;\n"
"inline void set_$name$(int index, $type$ value);\n"
"inline void add_$name$($type$ value);\n");
"inline const ::google::protobuf::RepeatedField< $type$ >& $name$() const\n"
" $deprecation$;\n"
"inline ::google::protobuf::RepeatedField< $type$ >* mutable_$name$()$deprecation$;\n"
"inline $type$ $name$(int index) const$deprecation$;\n"
"inline void set_$name$(int index, $type$ value)$deprecation$;\n"
"inline void add_$name$($type$ value)$deprecation$;\n");
}
void RepeatedPrimitiveFieldGenerator::
@ -272,12 +263,12 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::uint32 length;\n"
"DO_(input->ReadVarint32(&length));\n"
"::google::protobuf::io::CodedInputStream::Limit limit = "
"input->PushLimit(length);\n"
"::google::protobuf::io::CodedInputStream::Limit limit =\n"
" input->PushLimit(length);\n"
"while (input->BytesUntilLimit() > 0) {\n"
" $type$ value;\n"
" DO_(::google::protobuf::internal::WireFormat::Read$declared_type$("
"input, &value));\n"
" DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
" input, &value));\n"
" add_$name$(value);\n"
"}\n"
"input->PopLimit(limit);\n");
@ -286,8 +277,8 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
} else {
printer->Print(variables_,
"$type$ value;\n"
"DO_(::google::protobuf::internal::WireFormat::Read$declared_type$("
"input, &value));\n"
"DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
" input, &value));\n"
"add_$name$(value);\n");
}
}
@ -298,9 +289,9 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
// Write the tag and the size.
printer->Print(variables_,
"if (this->$name$_size() > 0) {\n"
" ::google::protobuf::internal::WireFormat::WriteTag("
" ::google::protobuf::internal::WireFormatLite::WriteTag("
"$number$, "
"::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED, "
"::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, "
"output);\n"
" output->WriteVarint32(_$name$_cached_byte_size_);\n"
"}\n");
@ -309,12 +300,12 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
"for (int i = 0; i < this->$name$_size(); i++) {\n");
if (descriptor_->options().packed()) {
printer->Print(variables_,
" ::google::protobuf::internal::WireFormat::Write$declared_type$NoTag("
"this->$name$(i), output);\n");
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n"
" this->$name$(i), output);\n");
} else {
printer->Print(variables_,
" ::google::protobuf::internal::WireFormat::Write$declared_type$("
"$number$, this->$name$(i), output);\n");
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
" $number$, this->$name$(i), output);\n");
}
printer->Print("}\n");
}
@ -325,26 +316,24 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
// Write the tag and the size.
printer->Print(variables_,
"if (this->$name$_size() > 0) {\n"
" target = ::google::protobuf::internal::WireFormat::WriteTagToArray("
"$number$, "
"::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED, "
"target);\n"
" target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray("
"_$name$_cached_byte_size_, target);\n"
" target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n"
" $number$,\n"
" ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
" target);\n"
" target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(\n"
" _$name$_cached_byte_size_, target);\n"
"}\n");
}
printer->Print(variables_,
"for (int i = 0; i < this->$name$_size(); i++) {\n");
if (descriptor_->options().packed()) {
printer->Print(variables_,
" target = ::google::protobuf::internal::WireFormat::"
"Write$declared_type$NoTagToArray("
"this->$name$(i), target);\n");
" target = ::google::protobuf::internal::WireFormatLite::\n"
" Write$declared_type$NoTagToArray(this->$name$(i), target);\n");
} else {
printer->Print(variables_,
" target = ::google::protobuf::internal::WireFormat::"
"Write$declared_type$ToArray("
"$number$, this->$name$(i), target);\n");
" target = ::google::protobuf::internal::WireFormatLite::\n"
" Write$declared_type$ToArray($number$, this->$name$(i), target);\n");
}
printer->Print("}\n");
}
@ -359,8 +348,8 @@ GenerateByteSize(io::Printer* printer) const {
if (fixed_size == -1) {
printer->Print(variables_,
"for (int i = 0; i < this->$name$_size(); i++) {\n"
" data_size += ::google::protobuf::internal::WireFormat::$declared_type$Size(\n"
" this->$name$(i));\n"
" data_size += ::google::protobuf::internal::WireFormatLite::\n"
" $declared_type$Size(this->$name$(i));\n"
"}\n");
} else {
printer->Print(variables_,
@ -370,8 +359,8 @@ GenerateByteSize(io::Printer* printer) const {
if (descriptor_->options().packed()) {
printer->Print(variables_,
"if (data_size > 0) {\n"
" total_size += $tag_size$ + "
"::google::protobuf::internal::WireFormat::Int32Size(data_size);\n"
" total_size += $tag_size$ +\n"
" ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
"}\n"
"_$name$_cached_byte_size_ = data_size;\n"
"total_size += data_size;\n");

View File

@ -249,7 +249,7 @@ void ServiceGenerator::GenerateCallMethod(io::Printer* printer) {
sub_vars["input_type"] = ClassName(method->input_type(), true);
sub_vars["output_type"] = ClassName(method->output_type(), true);
// Note: ::google::protobuf::down_cast does not work here because it only works on pointers,
// Note: down_cast does not work here because it only works on pointers,
// not references.
printer->Print(sub_vars,
" case $index$:\n"

View File

@ -35,7 +35,6 @@
#include <google/protobuf/compiler/cpp/cpp_string_field.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format_inl.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/stubs/strutil.h>
@ -44,23 +43,13 @@ namespace protobuf {
namespace compiler {
namespace cpp {
using internal::WireFormat;
namespace {
// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
// repeat code between this and the other field types.
void SetStringVariables(const FieldDescriptor* descriptor,
map<string, string>* variables) {
(*variables)["name"] = FieldName(descriptor);
SetCommonFieldVariables(descriptor, variables);
(*variables)["default"] =
"\"" + CEscape(descriptor->default_value_string()) + "\"";
(*variables)["index"] = SimpleItoa(descriptor->index());
(*variables)["number"] = SimpleItoa(descriptor->number());
(*variables)["classname"] = ClassName(FieldScope(descriptor), false);
(*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
(*variables)["tag_size"] = SimpleItoa(
WireFormat::TagSize(descriptor->number(), descriptor->type()));
(*variables)["pointer_type"] =
descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
}
@ -111,11 +100,12 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
}
printer->Print(variables_,
"inline const ::std::string& $name$() const;\n"
"inline void set_$name$(const ::std::string& value);\n"
"inline void set_$name$(const char* value);\n"
"inline void set_$name$(const $pointer_type$* value, size_t size);\n"
"inline ::std::string* mutable_$name$();\n");
"inline const ::std::string& $name$() const$deprecation$;\n"
"inline void set_$name$(const ::std::string& value)$deprecation$;\n"
"inline void set_$name$(const char* value)$deprecation$;\n"
"inline void set_$name$(const $pointer_type$* value, size_t size)"
"$deprecation$;\n"
"inline ::std::string* mutable_$name$()$deprecation$;\n");
if (descriptor_->options().has_ctype()) {
printer->Outdent();
@ -221,29 +211,52 @@ GenerateDestructorCode(io::Printer* printer) const {
void StringFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormat::Read$declared_type$("
"input, mutable_$name$()));\n");
"DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
" input, this->mutable_$name$()));\n");
if (HasUtf8Verification(descriptor_->file()) &&
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
printer->Print(variables_,
"::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
" this->$name$().data(), this->$name$().length(),\n"
" ::google::protobuf::internal::WireFormat::PARSE);\n");
}
}
void StringFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
if (HasUtf8Verification(descriptor_->file()) &&
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
printer->Print(variables_,
"::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
" this->$name$().data(), this->$name$().length(),\n"
" ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
}
printer->Print(variables_,
"::google::protobuf::internal::WireFormat::Write$declared_type$("
"$number$, this->$name$(), output);\n");
"::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
" $number$, this->$name$(), output);\n");
}
void StringFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
if (HasUtf8Verification(descriptor_->file()) &&
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
printer->Print(variables_,
"::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
" this->$name$().data(), this->$name$().length(),\n"
" ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
}
printer->Print(variables_,
"target = ::google::protobuf::internal::WireFormat::Write$declared_type$ToArray("
"$number$, this->$name$(), target);\n");
"target =\n"
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray(\n"
" $number$, this->$name$(), target);\n");
}
void StringFieldGenerator::
GenerateByteSize(io::Printer* printer) const {
printer->Print(variables_,
"total_size += $tag_size$ +\n"
" ::google::protobuf::internal::WireFormat::$declared_type$Size(this->$name$());\n");
" ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
" this->$name$());\n");
}
// ===================================================================
@ -274,18 +287,22 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
}
printer->Print(variables_,
"inline const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const;\n"
"inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$();\n"
"inline const ::std::string& $name$(int index) const;\n"
"inline ::std::string* mutable_$name$(int index);\n"
"inline void set_$name$(int index, const ::std::string& value);\n"
"inline void set_$name$(int index, const char* value);\n"
"inline const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const"
"$deprecation$;\n"
"inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()"
"$deprecation$;\n"
"inline const ::std::string& $name$(int index) const$deprecation$;\n"
"inline ::std::string* mutable_$name$(int index)$deprecation$;\n"
"inline void set_$name$(int index, const ::std::string& value)$deprecation$;\n"
"inline void set_$name$(int index, const char* value)$deprecation$;\n"
"inline "
"void set_$name$(int index, const $pointer_type$* value, size_t size);\n"
"inline ::std::string* add_$name$();\n"
"inline void add_$name$(const ::std::string& value);\n"
"inline void add_$name$(const char* value);\n"
"inline void add_$name$(const $pointer_type$* value, size_t size);\n");
"void set_$name$(int index, const $pointer_type$* value, size_t size)"
"$deprecation$;\n"
"inline ::std::string* add_$name$()$deprecation$;\n"
"inline void add_$name$(const ::std::string& value)$deprecation$;\n"
"inline void add_$name$(const char* value)$deprecation$;\n"
"inline void add_$name$(const $pointer_type$* value, size_t size)"
"$deprecation$;\n");
if (descriptor_->options().has_ctype()) {
printer->Outdent();
@ -361,26 +378,48 @@ GenerateConstructorCode(io::Printer* printer) const {
void RepeatedStringFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormat::Read$declared_type$(\n"
" input, add_$name$()));\n");
"DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
" input, this->add_$name$()));\n");
if (HasUtf8Verification(descriptor_->file()) &&
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
printer->Print(variables_,
"::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
" this->$name$(0).data(), this->$name$(0).length(),\n"
" ::google::protobuf::internal::WireFormat::PARSE);\n");
}
}
void RepeatedStringFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
printer->Print(variables_,
"for (int i = 0; i < this->$name$_size(); i++) {\n"
" ::google::protobuf::internal::WireFormat::Write$declared_type$("
"$number$, this->$name$(i), output);\n"
"for (int i = 0; i < this->$name$_size(); i++) {\n");
if (HasUtf8Verification(descriptor_->file()) &&
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
printer->Print(variables_,
"::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
" this->$name$(i).data(), this->$name$(i).length(),\n"
" ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
}
printer->Print(variables_,
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
" $number$, this->$name$(i), output);\n"
"}\n");
}
void RepeatedStringFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
printer->Print(variables_,
"for (int i = 0; i < this->$name$_size(); i++) {\n"
" target = ::google::protobuf::internal::WireFormat::"
"Write$declared_type$ToArray("
"$number$, this->$name$(i), target);\n"
"for (int i = 0; i < this->$name$_size(); i++) {\n");
if (HasUtf8Verification(descriptor_->file()) &&
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
printer->Print(variables_,
" ::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
" this->$name$(i).data(), this->$name$(i).length(),\n"
" ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
}
printer->Print(variables_,
" target = ::google::protobuf::internal::WireFormatLite::\n"
" Write$declared_type$ToArray($number$, this->$name$(i), target);\n"
"}\n");
}
@ -389,7 +428,7 @@ GenerateByteSize(io::Printer* printer) const {
printer->Print(variables_,
"total_size += $tag_size$ * this->$name$_size();\n"
"for (int i = 0; i < this->$name$_size(); i++) {\n"
" total_size += ::google::protobuf::internal::WireFormat::$declared_type$Size(\n"
" total_size += ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
" this->$name$(i));\n"
"}\n");
}

View File

@ -50,11 +50,9 @@
#include <google/protobuf/unittest_optimize_for.pb.h>
#include <google/protobuf/unittest_embed_optimize_for.pb.h>
#include <google/protobuf/test_util.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h>
#include <google/protobuf/compiler/importer.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/tokenizer.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
@ -75,18 +73,6 @@ namespace cpp {
// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
namespace cpp_unittest {
TEST(ExtremeDefaultValues, FloatingPoint) {
const unittest::TestExtremeDefaultValues& extreme_default =
unittest::TestExtremeDefaultValues::default_instance();
EXPECT_EQ(0.0f, extreme_default.zero_float());
EXPECT_EQ(1.0f, extreme_default.one_float());
EXPECT_EQ(1.5f, extreme_default.small_float());
EXPECT_EQ(-1.0f, extreme_default.negative_one_float());
EXPECT_EQ(-1.5f, extreme_default.negative_float());
EXPECT_EQ(2.0e8f, extreme_default.large_float());
EXPECT_EQ(-8e-28f, extreme_default.small_negative_float());
}
class MockErrorCollector : public MultiFileErrorCollector {
public:
@ -157,6 +143,19 @@ TEST(GeneratedMessageTest, Defaults) {
&message.optional_import_message());
}
TEST(GeneratedMessageTest, FloatingPointDefaults) {
const unittest::TestExtremeDefaultValues& extreme_default =
unittest::TestExtremeDefaultValues::default_instance();
EXPECT_EQ(0.0f, extreme_default.zero_float());
EXPECT_EQ(1.0f, extreme_default.one_float());
EXPECT_EQ(1.5f, extreme_default.small_float());
EXPECT_EQ(-1.0f, extreme_default.negative_one_float());
EXPECT_EQ(-1.5f, extreme_default.negative_float());
EXPECT_EQ(2.0e8f, extreme_default.large_float());
EXPECT_EQ(-8e-28f, extreme_default.small_negative_float());
}
TEST(GeneratedMessageTest, Accessors) {
// Set every field to a unique value then go back and check all those
// values.
@ -710,6 +709,32 @@ TEST(GeneratedMessageTest, TestSpaceUsed) {
#endif // !PROTOBUF_TEST_NO_DESCRIPTORS
TEST(GeneratedMessageTest, FieldConstantValues) {
unittest::TestRequired message;
EXPECT_EQ(unittest::TestAllTypes_NestedMessage::kBbFieldNumber, 1);
EXPECT_EQ(unittest::TestAllTypes::kOptionalInt32FieldNumber, 1);
EXPECT_EQ(unittest::TestAllTypes::kOptionalgroupFieldNumber, 16);
EXPECT_EQ(unittest::TestAllTypes::kOptionalNestedMessageFieldNumber, 18);
EXPECT_EQ(unittest::TestAllTypes::kOptionalNestedEnumFieldNumber, 21);
EXPECT_EQ(unittest::TestAllTypes::kRepeatedInt32FieldNumber, 31);
EXPECT_EQ(unittest::TestAllTypes::kRepeatedgroupFieldNumber, 46);
EXPECT_EQ(unittest::TestAllTypes::kRepeatedNestedMessageFieldNumber, 48);
EXPECT_EQ(unittest::TestAllTypes::kRepeatedNestedEnumFieldNumber, 51);
}
TEST(GeneratedMessageTest, ExtensionConstantValues) {
EXPECT_EQ(unittest::TestRequired::kSingleFieldNumber, 1000);
EXPECT_EQ(unittest::TestRequired::kMultiFieldNumber, 1001);
EXPECT_EQ(unittest::kOptionalInt32ExtensionFieldNumber, 1);
EXPECT_EQ(unittest::kOptionalgroupExtensionFieldNumber, 16);
EXPECT_EQ(unittest::kOptionalNestedMessageExtensionFieldNumber, 18);
EXPECT_EQ(unittest::kOptionalNestedEnumExtensionFieldNumber, 21);
EXPECT_EQ(unittest::kRepeatedInt32ExtensionFieldNumber, 31);
EXPECT_EQ(unittest::kRepeatedgroupExtensionFieldNumber, 46);
EXPECT_EQ(unittest::kRepeatedNestedMessageExtensionFieldNumber, 48);
EXPECT_EQ(unittest::kRepeatedNestedEnumExtensionFieldNumber, 51);
}
// ===================================================================
TEST(GeneratedEnumTest, EnumValuesAsSwitchCases) {
@ -803,6 +828,17 @@ TEST(GeneratedEnumTest, Parse) {
EXPECT_FALSE(unittest::TestEnumWithDupValue_Parse("FOO", &dup_value));
}
TEST(GeneratedEnumTest, GetEnumDescriptor) {
EXPECT_EQ(unittest::TestAllTypes::NestedEnum_descriptor(),
GetEnumDescriptor<unittest::TestAllTypes::NestedEnum>());
EXPECT_EQ(unittest::ForeignEnum_descriptor(),
GetEnumDescriptor<unittest::ForeignEnum>());
EXPECT_EQ(unittest::TestEnumWithDupValue_descriptor(),
GetEnumDescriptor<unittest::TestEnumWithDupValue>());
EXPECT_EQ(unittest::TestSparseEnum_descriptor(),
GetEnumDescriptor<unittest::TestSparseEnum>());
}
#endif // PROTOBUF_TEST_NO_DESCRIPTORS
// ===================================================================

View File

@ -67,14 +67,17 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor)
EnumGenerator::~EnumGenerator() {}
void EnumGenerator::Generate(io::Printer* printer) {
bool is_own_file =
descriptor_->containing_type() == NULL &&
descriptor_->file()->options().java_multiple_files();
printer->Print(
"public $static$ enum $classname$\n"
" implements com.google.protobuf.ProtocolMessageEnum {\n",
"static", is_own_file ? "" : "static",
"classname", descriptor_->name());
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
"public enum $classname$\n"
" implements com.google.protobuf.ProtocolMessageEnum {\n",
"classname", descriptor_->name());
} else {
printer->Print(
"public enum $classname$\n"
" implements com.google.protobuf.Internal.EnumLite {\n",
"classname", descriptor_->name());
}
printer->Indent();
for (int i = 0; i < canonical_values_.size(); i++) {
@ -126,63 +129,78 @@ void EnumGenerator::Generate(io::Printer* printer) {
" default: return null;\n"
" }\n"
"}\n"
"\n");
"\n"
"public static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n"
" internalGetValueMap() {\n"
" return internalValueMap;\n"
"}\n"
"private static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n"
" internalValueMap =\n"
" new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n"
" public $classname$ findValueByNumber(int number) {\n"
" return $classname$.valueOf(number)\n;"
" }\n"
" };\n"
"\n",
"classname", descriptor_->name());
// -----------------------------------------------------------------
// Reflection
printer->Print(
"public final com.google.protobuf.Descriptors.EnumValueDescriptor\n"
" getValueDescriptor() {\n"
" return getDescriptor().getValues().get(index);\n"
"}\n"
"public final com.google.protobuf.Descriptors.EnumDescriptor\n"
" getDescriptorForType() {\n"
" return getDescriptor();\n"
"}\n"
"public static final com.google.protobuf.Descriptors.EnumDescriptor\n"
" getDescriptor() {\n");
// TODO(kenton): Cache statically? Note that we can't access descriptors
// at module init time because it wouldn't work with descriptor.proto, but
// we can cache the value the first time getDescriptor() is called.
if (descriptor_->containing_type() == NULL) {
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
" return $file$.getDescriptor().getEnumTypes().get($index$);\n",
"file", ClassName(descriptor_->file()),
"index", SimpleItoa(descriptor_->index()));
} else {
"public final com.google.protobuf.Descriptors.EnumValueDescriptor\n"
" getValueDescriptor() {\n"
" return getDescriptor().getValues().get(index);\n"
"}\n"
"public final com.google.protobuf.Descriptors.EnumDescriptor\n"
" getDescriptorForType() {\n"
" return getDescriptor();\n"
"}\n"
"public static final com.google.protobuf.Descriptors.EnumDescriptor\n"
" getDescriptor() {\n");
// TODO(kenton): Cache statically? Note that we can't access descriptors
// at module init time because it wouldn't work with descriptor.proto, but
// we can cache the value the first time getDescriptor() is called.
if (descriptor_->containing_type() == NULL) {
printer->Print(
" return $file$.getDescriptor().getEnumTypes().get($index$);\n",
"file", ClassName(descriptor_->file()),
"index", SimpleItoa(descriptor_->index()));
} else {
printer->Print(
" return $parent$.getDescriptor().getEnumTypes().get($index$);\n",
"parent", ClassName(descriptor_->containing_type()),
"index", SimpleItoa(descriptor_->index()));
}
printer->Print(
" return $parent$.getDescriptor().getEnumTypes().get($index$);\n",
"parent", ClassName(descriptor_->containing_type()),
"index", SimpleItoa(descriptor_->index()));
"}\n"
"\n"
"private static final $classname$[] VALUES = {\n"
" ",
"classname", descriptor_->name());
for (int i = 0; i < descriptor_->value_count(); i++) {
printer->Print("$name$, ",
"name", descriptor_->value(i)->name());
}
printer->Print(
"\n"
"};\n"
"public static $classname$ valueOf(\n"
" com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n"
" if (desc.getType() != getDescriptor()) {\n"
" throw new java.lang.IllegalArgumentException(\n"
" \"EnumValueDescriptor is not for this type.\");\n"
" }\n"
" return VALUES[desc.getIndex()];\n"
"}\n",
"classname", descriptor_->name());
}
printer->Print(
"}\n"
"\n"
"private static final $classname$[] VALUES = {\n"
" ",
"classname", descriptor_->name());
for (int i = 0; i < descriptor_->value_count(); i++) {
printer->Print("$name$, ",
"name", descriptor_->value(i)->name());
}
printer->Print(
"\n"
"};\n"
"public static $classname$ valueOf(\n"
" com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n"
" if (desc.getType() != getDescriptor()) {\n"
" throw new java.lang.IllegalArgumentException(\n"
" \"EnumValueDescriptor is not for this type.\");\n"
" }\n"
" return VALUES[desc.getIndex()];\n"
"}\n",
"classname", descriptor_->name());
// -----------------------------------------------------------------
printer->Print(
@ -194,14 +212,16 @@ void EnumGenerator::Generate(io::Printer* printer) {
"}\n",
"classname", descriptor_->name());
// Force the static initialization code for the file to run, since it may
// initialize static variables declared in this class.
printer->Print(
"\n"
"static {\n"
" $file$.getDescriptor();\n"
"}\n",
"file", ClassName(descriptor_->file()));
if (HasDescriptorMethods(descriptor_)) {
// Force the static initialization code for the file to run, since it may
// initialize static variables declared in this class.
printer->Print(
"\n"
"static {\n"
" $file$.getDescriptor();\n"
"}\n",
"file", ClassName(descriptor_->file()));
}
printer->Outdent();
printer->Print("}\n\n");

View File

@ -39,7 +39,7 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format_inl.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
@ -53,18 +53,13 @@ namespace {
// repeat code between this and the other field types.
void SetEnumVariables(const FieldDescriptor* descriptor,
map<string, string>* variables) {
const EnumValueDescriptor* default_value;
default_value = descriptor->default_value_enum();
string type = ClassName(descriptor->enum_type());
(*variables)["name"] =
UnderscoresToCamelCase(descriptor);
(*variables)["capitalized_name"] =
UnderscoresToCapitalizedCamelCase(descriptor);
(*variables)["number"] = SimpleItoa(descriptor->number());
(*variables)["type"] = type;
(*variables)["default"] = type + "." + default_value->name();
(*variables)["type"] = ClassName(descriptor->enum_type());
(*variables)["default"] = DefaultValue(descriptor);
(*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
(*variables)["tag_size"] = SimpleItoa(
internal::WireFormat::TagSize(descriptor->number(), descriptor->type()));
@ -132,10 +127,17 @@ void EnumFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
printer->Print(variables_,
"int rawValue = input.readEnum();\n"
"$type$ value = $type$.valueOf(rawValue);\n"
"if (value == null) {\n"
" unknownFields.mergeVarintField($number$, rawValue);\n"
"} else {\n"
"$type$ value = $type$.valueOf(rawValue);\n");
if (HasUnknownFields(descriptor_->containing_type())) {
printer->Print(variables_,
"if (value == null) {\n"
" unknownFields.mergeVarintField($number$, rawValue);\n"
"} else {\n");
} else {
printer->Print(variables_,
"if (value != null) {\n");
}
printer->Print(variables_,
" set$capitalized_name$(value);\n"
"}\n");
}
@ -185,7 +187,7 @@ GenerateMembers(io::Printer* printer) const {
"}\n");
if (descriptor_->options().packed() &&
descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
HasGeneratedMethods(descriptor_->containing_type())) {
printer->Print(variables_,
"private int $name$MemoizedSerializedSize;\n");
}
@ -272,10 +274,17 @@ GenerateParsingCode(io::Printer* printer) const {
// Read and store the enum
printer->Print(variables_,
"int rawValue = input.readEnum();\n"
"$type$ value = $type$.valueOf(rawValue);\n"
"if (value == null) {\n"
" unknownFields.mergeVarintField($number$, rawValue);\n"
"} else {\n"
"$type$ value = $type$.valueOf(rawValue);\n");
if (HasUnknownFields(descriptor_->containing_type())) {
printer->Print(variables_,
"if (value == null) {\n"
" unknownFields.mergeVarintField($number$, rawValue);\n"
"} else {\n");
} else {
printer->Print(variables_,
"if (value != null) {\n");
}
printer->Print(variables_,
" add$capitalized_name$(value);\n"
"}\n");

View File

@ -42,6 +42,39 @@ namespace protobuf {
namespace compiler {
namespace java {
namespace {
const char* TypeName(FieldDescriptor::Type field_type) {
switch (field_type) {
case FieldDescriptor::TYPE_INT32 : return "INT32";
case FieldDescriptor::TYPE_UINT32 : return "UINT32";
case FieldDescriptor::TYPE_SINT32 : return "SINT32";
case FieldDescriptor::TYPE_FIXED32 : return "FIXED32";
case FieldDescriptor::TYPE_SFIXED32: return "SFIXED32";
case FieldDescriptor::TYPE_INT64 : return "INT64";
case FieldDescriptor::TYPE_UINT64 : return "UINT64";
case FieldDescriptor::TYPE_SINT64 : return "SINT64";
case FieldDescriptor::TYPE_FIXED64 : return "FIXED64";
case FieldDescriptor::TYPE_SFIXED64: return "SFIXED64";
case FieldDescriptor::TYPE_FLOAT : return "FLOAT";
case FieldDescriptor::TYPE_DOUBLE : return "DOUBLE";
case FieldDescriptor::TYPE_BOOL : return "BOOL";
case FieldDescriptor::TYPE_STRING : return "STRING";
case FieldDescriptor::TYPE_BYTES : return "BYTES";
case FieldDescriptor::TYPE_ENUM : return "ENUM";
case FieldDescriptor::TYPE_GROUP : return "GROUP";
case FieldDescriptor::TYPE_MESSAGE : return "MESSAGE";
// No default because we want the compiler to complain if any new
// types are added.
}
GOOGLE_LOG(FATAL) << "Can't get here.";
return NULL;
}
}
ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor)
: descriptor_(descriptor) {
if (descriptor_->extension_scope() != NULL) {
@ -59,6 +92,7 @@ void ExtensionGenerator::Generate(io::Printer* printer) {
vars["containing_type"] = ClassName(descriptor_->containing_type());
vars["number"] = SimpleItoa(descriptor_->number());
vars["constant_name"] = FieldConstantName(descriptor_);
vars["lite"] = HasDescriptorMethods(descriptor_->file()) ? "" : "Lite";
JavaType java_type = GetJavaType(descriptor_);
string singular_type;
@ -79,13 +113,13 @@ void ExtensionGenerator::Generate(io::Printer* printer) {
if (descriptor_->is_repeated()) {
printer->Print(vars,
"public static\n"
" com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
" com.google.protobuf.GeneratedMessage$lite$.GeneratedExtension<\n"
" $containing_type$,\n"
" java.util.List<$type$>> $name$;\n");
} else {
printer->Print(vars,
"public static\n"
" com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
" com.google.protobuf.GeneratedMessage$lite$.GeneratedExtension<\n"
" $containing_type$,\n"
" $type$> $name$;\n");
}
@ -96,34 +130,71 @@ void ExtensionGenerator::GenerateInitializationCode(io::Printer* printer) {
vars["name"] = UnderscoresToCamelCase(descriptor_);
vars["scope"] = scope_;
vars["index"] = SimpleItoa(descriptor_->index());
vars["extendee"] = ClassName(descriptor_->containing_type());
vars["default"] = descriptor_->is_repeated() ? "" : DefaultValue(descriptor_);
vars["number"] = SimpleItoa(descriptor_->number());
vars["type_constant"] = TypeName(descriptor_->type());
vars["packed"] = descriptor_->options().packed() ? "true" : "false";
vars["enum_map"] = "null";
vars["prototype"] = "null";
JavaType java_type = GetJavaType(descriptor_);
string singular_type;
switch (java_type) {
case JAVATYPE_MESSAGE:
vars["type"] = ClassName(descriptor_->message_type());
vars["prototype"] = ClassName(descriptor_->message_type()) +
".getDefaultInstance()";
break;
case JAVATYPE_ENUM:
vars["type"] = ClassName(descriptor_->enum_type());
vars["enum_map"] = ClassName(descriptor_->enum_type()) +
".internalGetValueMap()";
break;
default:
vars["type"] = BoxedPrimitiveTypeName(java_type);
break;
}
if (descriptor_->is_repeated()) {
printer->Print(vars,
"$scope$.$name$ =\n"
" com.google.protobuf.GeneratedMessage\n"
" .newRepeatedGeneratedExtension(\n"
" $scope$.getDescriptor().getExtensions().get($index$),\n"
" $type$.class);\n");
if (HasDescriptorMethods(descriptor_->file())) {
if (descriptor_->is_repeated()) {
printer->Print(vars,
"$scope$.$name$ =\n"
" com.google.protobuf.GeneratedMessage\n"
" .newRepeatedGeneratedExtension(\n"
" $scope$.getDescriptor().getExtensions().get($index$),\n"
" $type$.class);\n");
} else {
printer->Print(vars,
"$scope$.$name$ =\n"
" com.google.protobuf.GeneratedMessage.newGeneratedExtension(\n"
" $scope$.getDescriptor().getExtensions().get($index$),\n"
" $type$.class);\n");
}
} else {
printer->Print(vars,
"$scope$.$name$ =\n"
" com.google.protobuf.GeneratedMessage.newGeneratedExtension(\n"
" $scope$.getDescriptor().getExtensions().get($index$),\n"
" $type$.class);\n");
if (descriptor_->is_repeated()) {
printer->Print(vars,
"$scope$.$name$ =\n"
" com.google.protobuf.GeneratedMessageLite\n"
" .newRepeatedGeneratedExtension(\n"
" $extendee$.getDefaultInstance(),\n"
" $prototype$,\n"
" $enum_map$,\n"
" $number$,\n"
" com.google.protobuf.WireFormat.FieldType.$type_constant$,\n"
" $packed$);\n");
} else {
printer->Print(vars,
"$scope$.$name$ =\n"
" com.google.protobuf.GeneratedMessageLite\n"
" .newGeneratedExtension(\n"
" $extendee$.getDefaultInstance(),\n"
" $default$,\n"
" $prototype$,\n"
" $enum_map$,\n"
" $number$,\n"
" com.google.protobuf.WireFormat.FieldType.$type_constant$);\n");
}
}
}

View File

@ -151,7 +151,9 @@ void FileGenerator::Generate(io::Printer* printer) {
printer->Print(
"public static void registerAllExtensions(\n"
" com.google.protobuf.ExtensionRegistry registry) {\n");
" com.google.protobuf.ExtensionRegistry$lite$ registry) {\n",
"lite", HasDescriptorMethods(file_) ? "" : "Lite");
printer->Indent();
for (int i = 0; i < file_->extension_count(); i++) {
@ -195,8 +197,42 @@ void FileGenerator::Generate(io::Printer* printer) {
printer->Print("\n");
// -----------------------------------------------------------------
if (HasDescriptorMethods(file_)) {
GenerateEmbeddedDescriptor(printer);
} else {
printer->Print(
"static {\n");
printer->Indent();
for (int i = 0; i < file_->message_type_count(); i++) {
// TODO(kenton): Reuse MessageGenerator objects?
MessageGenerator(file_->message_type(i))
.GenerateStaticVariableInitializers(printer);
}
for (int i = 0; i < file_->extension_count(); i++) {
// TODO(kenton): Reuse ExtensionGenerator objects?
ExtensionGenerator(file_->extension(i))
.GenerateInitializationCode(printer);
}
printer->Outdent();
printer->Print(
"}\n");
}
// Dummy function we can use to force the static initialization block to
// run. Needed by inner classes. Cannot be private due to
// java_multiple_files option.
printer->Print(
"\n"
"public static void internalForceInit() {}\n");
printer->Outdent();
printer->Print("}\n");
}
void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) {
// Embed the descriptor. We simply serialize the entire FileDescriptorProto
// and embed it as a string literal, which is parsed and built into real
// descriptors at initialization time. We unfortunately have to put it in
@ -310,9 +346,6 @@ void FileGenerator::Generate(io::Printer* printer) {
printer->Outdent();
printer->Print(
"}\n");
printer->Outdent();
printer->Print("}\n");
}
template<typename GeneratorClass, typename DescriptorClass>

View File

@ -81,6 +81,8 @@ class FileGenerator {
string java_package_;
string classname_;
void GenerateEmbeddedDescriptor(io::Printer* printer);
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
};

View File

@ -45,32 +45,6 @@ namespace protobuf {
namespace compiler {
namespace java {
namespace {
// Parses a set of comma-delimited name/value pairs, e.g.:
// "foo=bar,baz,qux=corge"
// parses to the pairs:
// ("foo", "bar"), ("baz", ""), ("qux", "corge")
void ParseOptions(const string& text, vector<pair<string, string> >* output) {
vector<string> parts;
SplitStringUsing(text, ",", &parts);
for (int i = 0; i < parts.size(); i++) {
string::size_type equals_pos = parts[i].find_first_of('=');
pair<string, string> value;
if (equals_pos == string::npos) {
value.first = parts[i];
value.second = "";
} else {
value.first = parts[i].substr(0, equals_pos);
value.second = parts[i].substr(equals_pos + 1);
}
output->push_back(value);
}
}
} // namespace
JavaGenerator::JavaGenerator() {}
JavaGenerator::~JavaGenerator() {}
@ -79,7 +53,7 @@ bool JavaGenerator::Generate(const FileDescriptor* file,
OutputDirectory* output_directory,
string* error) const {
vector<pair<string, string> > options;
ParseOptions(parameter, &options);
ParseGeneratorParameter(parameter, &options);
// -----------------------------------------------------------------
// parse generator options

View File

@ -37,6 +37,7 @@
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
namespace google {
namespace protobuf {
@ -243,6 +244,72 @@ const char* BoxedPrimitiveTypeName(JavaType type) {
return NULL;
}
bool AllAscii(const string& text) {
for (int i = 0; i < text.size(); i++) {
if ((text[i] & 0x80) != 0) {
return false;
}
}
return true;
}
string DefaultValue(const FieldDescriptor* field) {
// Switch on cpp_type since we need to know which default_value_* method
// of FieldDescriptor to call.
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
return SimpleItoa(field->default_value_int32());
case FieldDescriptor::CPPTYPE_UINT32:
// Need to print as a signed int since Java has no unsigned.
return SimpleItoa(static_cast<int32>(field->default_value_uint32()));
case FieldDescriptor::CPPTYPE_INT64:
return SimpleItoa(field->default_value_int64()) + "L";
case FieldDescriptor::CPPTYPE_UINT64:
return SimpleItoa(static_cast<int64>(field->default_value_uint64())) +
"L";
case FieldDescriptor::CPPTYPE_DOUBLE:
return SimpleDtoa(field->default_value_double()) + "D";
case FieldDescriptor::CPPTYPE_FLOAT:
return SimpleFtoa(field->default_value_float()) + "F";
case FieldDescriptor::CPPTYPE_BOOL:
return field->default_value_bool() ? "true" : "false";
case FieldDescriptor::CPPTYPE_STRING:
if (field->type() == FieldDescriptor::TYPE_BYTES) {
if (field->has_default_value()) {
// See comments in Internal.java for gory details.
return strings::Substitute(
"com.google.protobuf.Internal.bytesDefaultValue(\"$0\")",
CEscape(field->default_value_string()));
} else {
return "com.google.protobuf.ByteString.EMPTY";
}
} else {
if (AllAscii(field->default_value_string())) {
// All chars are ASCII. In this case CEscape() works fine.
return "\"" + CEscape(field->default_value_string()) + "\"";
} else {
// See comments in Internal.java for gory details.
return strings::Substitute(
"com.google.protobuf.Internal.stringDefaultValue(\"$0\")",
CEscape(field->default_value_string()));
}
}
case FieldDescriptor::CPPTYPE_ENUM:
return ClassName(field->enum_type()) + "." +
field->default_value_enum()->name();
case FieldDescriptor::CPPTYPE_MESSAGE:
return ClassName(field->message_type()) + ".getDefaultInstance()";
// No default because we want the compiler to complain if any new
// types are added.
}
GOOGLE_LOG(FATAL) << "Can't get here.";
return "";
}
} // namespace java
} // namespace compiler
} // namespace protobuf

View File

@ -36,6 +36,7 @@
#define GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__
#include <string>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
namespace google {
@ -115,6 +116,35 @@ inline JavaType GetJavaType(const FieldDescriptor* field) {
// types.
const char* BoxedPrimitiveTypeName(JavaType type);
string DefaultValue(const FieldDescriptor* field);
// Does this message class keep track of unknown fields?
inline bool HasUnknownFields(const Descriptor* descriptor) {
return descriptor->file()->options().optimize_for() !=
FileOptions::LITE_RUNTIME;
}
// Does this message class have generated parsing, serialization, and other
// standard methods for which reflection-based fallback implementations exist?
inline bool HasGeneratedMethods(const Descriptor* descriptor) {
return descriptor->file()->options().optimize_for() !=
FileOptions::CODE_SIZE;
}
// Does this message class have descriptor and reflection methods?
inline bool HasDescriptorMethods(const Descriptor* descriptor) {
return descriptor->file()->options().optimize_for() !=
FileOptions::LITE_RUNTIME;
}
inline bool HasDescriptorMethods(const EnumDescriptor* descriptor) {
return descriptor->file()->options().optimize_for() !=
FileOptions::LITE_RUNTIME;
}
inline bool HasDescriptorMethods(const FileDescriptor* descriptor) {
return descriptor->options().optimize_for() !=
FileOptions::LITE_RUNTIME;
}
} // namespace java
} // namespace compiler
} // namespace protobuf

View File

@ -41,7 +41,7 @@
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_inl.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/descriptor.pb.h>
namespace google {
@ -50,6 +50,7 @@ namespace compiler {
namespace java {
using internal::WireFormat;
using internal::WireFormatLite;
namespace {
@ -153,38 +154,41 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor)
MessageGenerator::~MessageGenerator() {}
void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
// Because descriptor.proto (com.google.protobuf.DescriptorProtos) is
// used in the construction of descriptors, we have a tricky bootstrapping
// problem. To help control static initialization order, we make sure all
// descriptors and other static data that depends on them are members of
// the outermost class in the file. This way, they will be initialized in
// a deterministic order.
if (HasDescriptorMethods(descriptor_)) {
// Because descriptor.proto (com.google.protobuf.DescriptorProtos) is
// used in the construction of descriptors, we have a tricky bootstrapping
// problem. To help control static initialization order, we make sure all
// descriptors and other static data that depends on them are members of
// the outermost class in the file. This way, they will be initialized in
// a deterministic order.
map<string, string> vars;
vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
vars["index"] = SimpleItoa(descriptor_->index());
vars["classname"] = ClassName(descriptor_);
if (descriptor_->containing_type() != NULL) {
vars["parent"] = UniqueFileScopeIdentifier(descriptor_->containing_type());
map<string, string> vars;
vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
vars["index"] = SimpleItoa(descriptor_->index());
vars["classname"] = ClassName(descriptor_);
if (descriptor_->containing_type() != NULL) {
vars["parent"] = UniqueFileScopeIdentifier(
descriptor_->containing_type());
}
if (descriptor_->file()->options().java_multiple_files()) {
// We can only make these package-private since the classes that use them
// are in separate files.
vars["private"] = "";
} else {
vars["private"] = "private ";
}
// The descriptor for this type.
printer->Print(vars,
"$private$static com.google.protobuf.Descriptors.Descriptor\n"
" internal_$identifier$_descriptor;\n");
// And the FieldAccessorTable.
printer->Print(vars,
"$private$static\n"
" com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
" internal_$identifier$_fieldAccessorTable;\n");
}
if (descriptor_->file()->options().java_multiple_files()) {
// We can only make these package-private since the classes that use them
// are in separate files.
vars["private"] = "";
} else {
vars["private"] = "private ";
}
// The descriptor for this type.
printer->Print(vars,
"$private$static com.google.protobuf.Descriptors.Descriptor\n"
" internal_$identifier$_descriptor;\n");
// And the FieldAccessorTable.
printer->Print(vars,
"$private$static\n"
" com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
" internal_$identifier$_fieldAccessorTable;\n");
// Generate static members for all nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
@ -196,41 +200,44 @@ void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
void MessageGenerator::GenerateStaticVariableInitializers(
io::Printer* printer) {
map<string, string> vars;
vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
vars["index"] = SimpleItoa(descriptor_->index());
vars["classname"] = ClassName(descriptor_);
if (descriptor_->containing_type() != NULL) {
vars["parent"] = UniqueFileScopeIdentifier(descriptor_->containing_type());
}
if (HasDescriptorMethods(descriptor_)) {
map<string, string> vars;
vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
vars["index"] = SimpleItoa(descriptor_->index());
vars["classname"] = ClassName(descriptor_);
if (descriptor_->containing_type() != NULL) {
vars["parent"] = UniqueFileScopeIdentifier(
descriptor_->containing_type());
}
// The descriptor for this type.
if (descriptor_->containing_type() == NULL) {
printer->Print(vars,
"internal_$identifier$_descriptor =\n"
" getDescriptor().getMessageTypes().get($index$);\n");
} else {
printer->Print(vars,
"internal_$identifier$_descriptor =\n"
" internal_$parent$_descriptor.getNestedTypes().get($index$);\n");
}
// The descriptor for this type.
if (descriptor_->containing_type() == NULL) {
printer->Print(vars,
"internal_$identifier$_descriptor =\n"
" getDescriptor().getMessageTypes().get($index$);\n");
} else {
printer->Print(vars,
"internal_$identifier$_descriptor =\n"
" internal_$parent$_descriptor.getNestedTypes().get($index$);\n");
}
// And the FieldAccessorTable.
printer->Print(vars,
"internal_$identifier$_fieldAccessorTable = new\n"
" com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n"
" internal_$identifier$_descriptor,\n"
" new java.lang.String[] { ");
for (int i = 0; i < descriptor_->field_count(); i++) {
printer->Print(
"\"$field_name$\", ",
"field_name",
UnderscoresToCapitalizedCamelCase(descriptor_->field(i)));
// And the FieldAccessorTable.
printer->Print(vars,
"internal_$identifier$_fieldAccessorTable = new\n"
" com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n"
" internal_$identifier$_descriptor,\n"
" new java.lang.String[] { ");
for (int i = 0; i < descriptor_->field_count(); i++) {
printer->Print(
"\"$field_name$\", ",
"field_name",
UnderscoresToCapitalizedCamelCase(descriptor_->field(i)));
}
printer->Print("},\n"
" $classname$.class,\n"
" $classname$.Builder.class);\n",
"classname", ClassName(descriptor_));
}
printer->Print("},\n"
" $classname$.class,\n"
" $classname$.Builder.class);\n",
"classname", ClassName(descriptor_));
// Generate static member initializers for all nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
@ -252,18 +259,35 @@ void MessageGenerator::Generate(io::Printer* printer) {
descriptor_->file()->options().java_multiple_files();
if (descriptor_->extension_range_count() > 0) {
printer->Print(
"public $static$ final class $classname$ extends\n"
" com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
" $classname$> {\n",
"static", is_own_file ? "" : "static",
"classname", descriptor_->name());
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
"public $static$ final class $classname$ extends\n"
" com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
" $classname$> {\n",
"static", is_own_file ? "" : "static",
"classname", descriptor_->name());
} else {
printer->Print(
"public $static$ final class $classname$ extends\n"
" com.google.protobuf.GeneratedMessageLite.ExtendableMessage<\n"
" $classname$> {\n",
"static", is_own_file ? "" : "static",
"classname", descriptor_->name());
}
} else {
printer->Print(
"public $static$ final class $classname$ extends\n"
" com.google.protobuf.GeneratedMessage {\n",
"static", is_own_file ? "" : "static",
"classname", descriptor_->name());
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
"public $static$ final class $classname$ extends\n"
" com.google.protobuf.GeneratedMessage {\n",
"static", is_own_file ? "" : "static",
"classname", descriptor_->name());
} else {
printer->Print(
"public $static$ final class $classname$ extends\n"
" com.google.protobuf.GeneratedMessageLite {\n",
"static", is_own_file ? "" : "static",
"classname", descriptor_->name());
}
}
printer->Indent();
printer->Print(
@ -280,20 +304,23 @@ void MessageGenerator::Generate(io::Printer* printer) {
"}\n"
"\n",
"classname", descriptor_->name());
printer->Print(
"public static final com.google.protobuf.Descriptors.Descriptor\n"
" getDescriptor() {\n"
" return $fileclass$.internal_$identifier$_descriptor;\n"
"}\n"
"\n"
"@Override\n"
"protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
" internalGetFieldAccessorTable() {\n"
" return $fileclass$.internal_$identifier$_fieldAccessorTable;\n"
"}\n"
"\n",
"fileclass", ClassName(descriptor_->file()),
"identifier", UniqueFileScopeIdentifier(descriptor_));
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
"public static final com.google.protobuf.Descriptors.Descriptor\n"
" getDescriptor() {\n"
" return $fileclass$.internal_$identifier$_descriptor;\n"
"}\n"
"\n"
"@Override\n"
"protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
" internalGetFieldAccessorTable() {\n"
" return $fileclass$.internal_$identifier$_fieldAccessorTable;\n"
"}\n"
"\n",
"fileclass", ClassName(descriptor_->file()),
"identifier", UniqueFileScopeIdentifier(descriptor_));
}
// Nested types and extensions
for (int i = 0; i < descriptor_->enum_type_count(); i++) {
@ -318,7 +345,7 @@ void MessageGenerator::Generate(io::Printer* printer) {
printer->Print("\n");
}
if (descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
if (HasGeneratedMethods(descriptor_)) {
GenerateIsInitialized(printer);
GenerateMessageSerializationMethods(printer);
}
@ -326,12 +353,23 @@ void MessageGenerator::Generate(io::Printer* printer) {
GenerateParseFromMethods(printer);
GenerateBuilder(printer);
// Force the static initialization code for the file to run, since it may
// initialize static variables declared in this class.
if (HasDescriptorMethods(descriptor_)) {
// Force the static initialization code for the file to run, since it may
// initialize static variables declared in this class.
printer->Print(
"\n"
"static {\n"
" $file$.getDescriptor();\n"
"}\n",
"file", ClassName(descriptor_->file()));
}
// Force initialization of outer class. Otherwise, nested extensions may
// not be initialized.
printer->Print(
"\n"
"static {\n"
" $file$.getDescriptor();\n"
" $file$.internalForceInit();\n"
"}\n",
"file", ClassName(descriptor_->file()));
@ -360,9 +398,18 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
printer->Indent();
if (descriptor_->extension_range_count() > 0) {
printer->Print(
"com.google.protobuf.GeneratedMessage.ExtendableMessage\n"
" .ExtensionWriter extensionWriter = newExtensionWriter();\n");
if (descriptor_->options().message_set_wire_format()) {
printer->Print(
"com.google.protobuf.GeneratedMessage$lite$.ExtendableMessage\n"
" .ExtensionWriter extensionWriter =\n"
" newMessageSetExtensionWriter();\n",
"lite", HasDescriptorMethods(descriptor_) ? "" : "Lite");
} else {
printer->Print(
"com.google.protobuf.GeneratedMessage$lite$.ExtendableMessage\n"
" .ExtensionWriter extensionWriter = newExtensionWriter();\n",
"lite", HasDescriptorMethods(descriptor_) ? "" : "Lite");
}
}
// Merge the fields and the extension ranges, both sorted by field number.
@ -380,12 +427,14 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
}
}
if (descriptor_->options().message_set_wire_format()) {
printer->Print(
"getUnknownFields().writeAsMessageSetTo(output);\n");
} else {
printer->Print(
"getUnknownFields().writeTo(output);\n");
if (HasUnknownFields(descriptor_)) {
if (descriptor_->options().message_set_wire_format()) {
printer->Print(
"getUnknownFields().writeAsMessageSetTo(output);\n");
} else {
printer->Print(
"getUnknownFields().writeTo(output);\n");
}
}
printer->Outdent();
@ -406,16 +455,23 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
}
if (descriptor_->extension_range_count() > 0) {
printer->Print(
"size += extensionsSerializedSize();\n");
if (descriptor_->options().message_set_wire_format()) {
printer->Print(
"size += extensionsSerializedSizeAsMessageSet();\n");
} else {
printer->Print(
"size += extensionsSerializedSize();\n");
}
}
if (descriptor_->options().message_set_wire_format()) {
printer->Print(
"size += getUnknownFields().getSerializedSizeAsMessageSet();\n");
} else {
printer->Print(
"size += getUnknownFields().getSerializedSize();\n");
if (HasUnknownFields(descriptor_)) {
if (descriptor_->options().message_set_wire_format()) {
printer->Print(
"size += getUnknownFields().getSerializedSizeAsMessageSet();\n");
} else {
printer->Print(
"size += getUnknownFields().getSerializedSize();\n");
}
}
printer->Outdent();
@ -439,7 +495,7 @@ GenerateParseFromMethods(io::Printer* printer) {
"}\n"
"public static $classname$ parseFrom(\n"
" com.google.protobuf.ByteString data,\n"
" com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws com.google.protobuf.InvalidProtocolBufferException {\n"
" return newBuilder().mergeFrom(data, extensionRegistry)\n"
" .buildParsed();\n"
@ -450,7 +506,7 @@ GenerateParseFromMethods(io::Printer* printer) {
"}\n"
"public static $classname$ parseFrom(\n"
" byte[] data,\n"
" com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws com.google.protobuf.InvalidProtocolBufferException {\n"
" return newBuilder().mergeFrom(data, extensionRegistry)\n"
" .buildParsed();\n"
@ -461,7 +517,7 @@ GenerateParseFromMethods(io::Printer* printer) {
"}\n"
"public static $classname$ parseFrom(\n"
" java.io.InputStream input,\n"
" com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
" return newBuilder().mergeFrom(input, extensionRegistry)\n"
" .buildParsed();\n"
@ -472,7 +528,7 @@ GenerateParseFromMethods(io::Printer* printer) {
"}\n"
"public static $classname$ parseDelimitedFrom(\n"
" java.io.InputStream input,\n"
" com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
" return newBuilder().mergeDelimitedFrom(input, extensionRegistry)\n"
" .buildParsed();\n"
@ -484,7 +540,7 @@ GenerateParseFromMethods(io::Printer* printer) {
"}\n"
"public static $classname$ parseFrom(\n"
" com.google.protobuf.CodedInputStream input,\n"
" com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n"
" return newBuilder().mergeFrom(input, extensionRegistry)\n"
" .buildParsed();\n"
@ -509,32 +565,57 @@ void MessageGenerator::GenerateSerializeOneExtensionRange(
void MessageGenerator::GenerateBuilder(io::Printer* printer) {
printer->Print(
"public static Builder newBuilder() { return new Builder(); }\n"
"public Builder newBuilderForType() { return new Builder(); }\n"
"public static Builder newBuilder() { return Builder.create(); }\n"
"public Builder newBuilderForType() { return newBuilder(); }\n"
"public static Builder newBuilder($classname$ prototype) {\n"
" return new Builder().mergeFrom(prototype);\n"
" return newBuilder().mergeFrom(prototype);\n"
"}\n"
"public Builder toBuilder() { return newBuilder(this); }\n"
"\n",
"classname", ClassName(descriptor_));
if (descriptor_->extension_range_count() > 0) {
printer->Print(
"public static final class Builder extends\n"
" com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n"
" $classname$, Builder> {\n",
"classname", ClassName(descriptor_));
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
"public static final class Builder extends\n"
" com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n"
" $classname$, Builder> {\n",
"classname", ClassName(descriptor_));
} else {
printer->Print(
"public static final class Builder extends\n"
" com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<\n"
" $classname$, Builder> {\n",
"classname", ClassName(descriptor_));
}
} else {
printer->Print(
"public static final class Builder extends\n"
" com.google.protobuf.GeneratedMessage.Builder<Builder> {\n",
"classname", ClassName(descriptor_));
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
"public static final class Builder extends\n"
" com.google.protobuf.GeneratedMessage.Builder<Builder> {\n",
"classname", ClassName(descriptor_));
} else {
printer->Print(
"public static final class Builder extends\n"
" com.google.protobuf.GeneratedMessageLite.Builder<\n"
" $classname$, Builder> {\n",
"classname", ClassName(descriptor_));
}
}
printer->Indent();
// By using a threadlocal queue, we do not have to worry about locking when
// accessing the queue. Current JDKs implement this very efficiently, using
// no locks themselves to acquire the value when needed.
printer->Print(
"private static final "
" com.google.protobuf.Internal.ThreadLocalQuickQueue<Builder> builders =\n"
" new com.google.protobuf.Internal.ThreadLocalQuickQueue<Builder>();\n"
"\n");
GenerateCommonBuilderMethods(printer);
if (descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
if (HasGeneratedMethods(descriptor_)) {
GenerateBuilderParsingMethods(printer);
}
@ -553,10 +634,19 @@ void MessageGenerator::GenerateBuilder(io::Printer* printer) {
void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
printer->Print(
"private $classname$ result;\n"
"\n"
"// Construct using $classname$.newBuilder()\n"
"private Builder() {}\n"
"\n"
"$classname$ result = new $classname$();\n"
"private static Builder create() {\n"
" Builder builder = builders.get().poll();\n"
" if (builder == null) {\n"
" builder = new Builder();\n"
" }\n"
" builder.result = new $classname$();\n"
" return builder;\n"
"}\n"
"\n"
"@Override\n"
"protected $classname$ internalGetResult() {\n"
@ -565,25 +655,38 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
"\n"
"@Override\n"
"public Builder clear() {\n"
" if (result == null) {\n"
" throw new IllegalStateException(\n"
" \"Cannot call clear() after build().\");\n"
" }\n"
" result = new $classname$();\n"
" return this;\n"
"}\n"
"\n"
"@Override\n"
"public Builder clone() {\n"
" return new Builder().mergeFrom(result);\n"
" return create().mergeFrom(result);\n"
"}\n"
"\n"
"@Override\n"
"public com.google.protobuf.Descriptors.Descriptor\n"
" getDescriptorForType() {\n"
" return $classname$.getDescriptor();\n"
"}\n"
"\n"
"\n",
"classname", ClassName(descriptor_));
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
"@Override\n"
"public com.google.protobuf.Descriptors.Descriptor\n"
" getDescriptorForType() {\n"
" return $classname$.getDescriptor();\n"
"}\n"
"\n",
"classname", ClassName(descriptor_));
}
printer->Print(
"public $classname$ getDefaultInstanceForType() {\n"
" return $classname$.getDefaultInstance();\n"
"}\n"
"\n",
"\n"
"public boolean isInitialized() {\n"
" return result.isInitialized();\n"
"}\n",
"classname", ClassName(descriptor_));
// -----------------------------------------------------------------
@ -592,8 +695,7 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
"public $classname$ build() {\n"
// If result == null, we'll throw an appropriate exception later.
" if (result != null && !isInitialized()) {\n"
" throw new com.google.protobuf.UninitializedMessageException(\n"
" result);\n"
" throw newUninitializedMessageException(result);\n"
" }\n"
" return buildPartial();\n"
"}\n"
@ -601,7 +703,7 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
"private $classname$ buildParsed()\n"
" throws com.google.protobuf.InvalidProtocolBufferException {\n"
" if (!isInitialized()) {\n"
" throw new com.google.protobuf.UninitializedMessageException(\n"
" throw newUninitializedMessageException(\n"
" result).asInvalidProtocolBufferException();\n"
" }\n"
" return buildPartial();\n"
@ -610,7 +712,7 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
"public $classname$ buildPartial() {\n"
" if (result == null) {\n"
" throw new IllegalStateException(\n"
" \"build() has already been called on this Builder.\");"
" \"build() has already been called on this Builder.\");\n"
" }\n",
"classname", ClassName(descriptor_));
printer->Indent();
@ -623,6 +725,7 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
printer->Print(
" $classname$ returnMe = result;\n"
" result = null;\n"
" builders.get().offer(this);\n"
" return returnMe;\n"
"}\n"
"\n",
@ -630,18 +733,25 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
// -----------------------------------------------------------------
if (descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
if (HasGeneratedMethods(descriptor_)) {
// MergeFrom(Message other) requires the ability to distinguish the other
// messages type by its descriptor.
if (HasDescriptorMethods(descriptor_)) {
printer->Print(
"@Override\n"
"public Builder mergeFrom(com.google.protobuf.Message other) {\n"
" if (other instanceof $classname$) {\n"
" return mergeFrom(($classname$)other);\n"
" } else {\n"
" super.mergeFrom(other);\n"
" return this;\n"
" }\n"
"}\n"
"\n",
"classname", ClassName(descriptor_));
}
printer->Print(
"@Override\n"
"public Builder mergeFrom(com.google.protobuf.Message other) {\n"
" if (other instanceof $classname$) {\n"
" return mergeFrom(($classname$)other);\n"
" } else {\n"
" super.mergeFrom(other);\n"
" return this;\n"
" }\n"
"}\n"
"\n"
"public Builder mergeFrom($classname$ other) {\n"
// Optimization: If other is the default instance, we know none of its
// fields are set so we can skip the merge.
@ -661,8 +771,12 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
" this.mergeExtensionFields(other);\n");
}
if (HasUnknownFields(descriptor_)) {
printer->Print(
" this.mergeUnknownFields(other.getUnknownFields());\n");
}
printer->Print(
" this.mergeUnknownFields(other.getUnknownFields());\n"
" return this;\n"
"}\n"
"\n");
@ -676,25 +790,21 @@ void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) {
SortFieldsByNumber(descriptor_));
printer->Print(
"@Override\n"
"public Builder mergeFrom(\n"
" com.google.protobuf.CodedInputStream input)\n"
" throws java.io.IOException {\n"
" return mergeFrom(input,\n"
" com.google.protobuf.ExtensionRegistry.getEmptyRegistry());\n"
"}\n"
"\n"
"@Override\n"
"public Builder mergeFrom(\n"
" com.google.protobuf.CodedInputStream input,\n"
" com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
" com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
" throws java.io.IOException {\n");
printer->Indent();
if (HasUnknownFields(descriptor_)) {
printer->Print(
"com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n"
" com.google.protobuf.UnknownFieldSet.newBuilder(\n"
" this.getUnknownFields());\n");
}
printer->Print(
"com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n"
" com.google.protobuf.UnknownFieldSet.newBuilder(\n"
" this.getUnknownFields());\n"
"while (true) {\n");
printer->Indent();
@ -703,22 +813,34 @@ void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) {
"switch (tag) {\n");
printer->Indent();
printer->Print(
"case 0:\n" // zero signals EOF / limit reached
" this.setUnknownFields(unknownFields.build());\n"
" return this;\n"
"default: {\n"
" if (!parseUnknownField(input, unknownFields,\n"
" extensionRegistry, tag)) {\n"
" this.setUnknownFields(unknownFields.build());\n"
" return this;\n" // it's an endgroup tag
" }\n"
" break;\n"
"}\n");
if (HasUnknownFields(descriptor_)) {
printer->Print(
"case 0:\n" // zero signals EOF / limit reached
" this.setUnknownFields(unknownFields.build());\n"
" return this;\n"
"default: {\n"
" if (!parseUnknownField(input, unknownFields,\n"
" extensionRegistry, tag)) {\n"
" this.setUnknownFields(unknownFields.build());\n"
" return this;\n" // it's an endgroup tag
" }\n"
" break;\n"
"}\n");
} else {
printer->Print(
"case 0:\n" // zero signals EOF / limit reached
" return this;\n"
"default: {\n"
" if (!parseUnknownField(input, extensionRegistry, tag)) {\n"
" return this;\n" // it's an endgroup tag
" }\n"
" break;\n"
"}\n");
}
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = sorted_fields[i];
uint32 tag = WireFormat::MakeTag(field->number(),
uint32 tag = WireFormatLite::MakeTag(field->number(),
WireFormat::WireTypeForField(field));
printer->Print(

View File

@ -39,9 +39,8 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format_inl.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
namespace google {
namespace protobuf {
@ -49,6 +48,7 @@ namespace compiler {
namespace java {
using internal::WireFormat;
using internal::WireFormatLite;
namespace {
@ -121,16 +121,6 @@ const char* GetCapitalizedType(const FieldDescriptor* field) {
return NULL;
}
bool AllPrintableAscii(const string& text) {
// Cannot use isprint() because it's locale-specific. :(
for (int i = 0; i < text.size(); i++) {
if ((text[i] < 0x20) || text[i] >= 0x7F) {
return false;
}
}
return true;
}
// For encodings with fixed sizes, returns that size in bytes. Otherwise
// returns -1.
int FixedSize(FieldDescriptor::Type type) {
@ -141,14 +131,14 @@ int FixedSize(FieldDescriptor::Type type) {
case FieldDescriptor::TYPE_UINT64 : return -1;
case FieldDescriptor::TYPE_SINT32 : return -1;
case FieldDescriptor::TYPE_SINT64 : return -1;
case FieldDescriptor::TYPE_FIXED32 : return WireFormat::kFixed32Size;
case FieldDescriptor::TYPE_FIXED64 : return WireFormat::kFixed64Size;
case FieldDescriptor::TYPE_SFIXED32: return WireFormat::kSFixed32Size;
case FieldDescriptor::TYPE_SFIXED64: return WireFormat::kSFixed64Size;
case FieldDescriptor::TYPE_FLOAT : return WireFormat::kFloatSize;
case FieldDescriptor::TYPE_DOUBLE : return WireFormat::kDoubleSize;
case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size;
case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size;
case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size;
case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size;
case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize;
case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize;
case FieldDescriptor::TYPE_BOOL : return WireFormat::kBoolSize;
case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize;
case FieldDescriptor::TYPE_ENUM : return -1;
case FieldDescriptor::TYPE_STRING : return -1;
@ -163,64 +153,6 @@ int FixedSize(FieldDescriptor::Type type) {
return -1;
}
string DefaultValue(const FieldDescriptor* field) {
// Switch on cpp_type since we need to know which default_value_* method
// of FieldDescriptor to call.
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
return SimpleItoa(field->default_value_int32());
case FieldDescriptor::CPPTYPE_UINT32:
// Need to print as a signed int since Java has no unsigned.
return SimpleItoa(static_cast<int32>(field->default_value_uint32()));
case FieldDescriptor::CPPTYPE_INT64:
return SimpleItoa(field->default_value_int64()) + "L";
case FieldDescriptor::CPPTYPE_UINT64:
return SimpleItoa(static_cast<int64>(field->default_value_uint64())) +
"L";
case FieldDescriptor::CPPTYPE_DOUBLE:
return SimpleDtoa(field->default_value_double()) + "D";
case FieldDescriptor::CPPTYPE_FLOAT:
return SimpleFtoa(field->default_value_float()) + "F";
case FieldDescriptor::CPPTYPE_BOOL:
return field->default_value_bool() ? "true" : "false";
case FieldDescriptor::CPPTYPE_STRING: {
bool isBytes = field->type() == FieldDescriptor::TYPE_BYTES;
if (!isBytes && AllPrintableAscii(field->default_value_string())) {
// All chars are ASCII and printable. In this case CEscape() works
// fine (it will only escape quotes and backslashes).
// Note: If this "optimization" is removed, DescriptorProtos will
// no longer be able to initialize itself due to bootstrapping
// problems.
return "\"" + CEscape(field->default_value_string()) + "\"";
}
if (isBytes && !field->has_default_value()) {
return "com.google.protobuf.ByteString.EMPTY";
}
// Escaping strings correctly for Java and generating efficient
// initializers for ByteStrings are both tricky. We can sidestep the
// whole problem by just grabbing the default value from the descriptor.
return strings::Substitute(
"(($0) $1.getDescriptor().getFields().get($2).getDefaultValue())",
isBytes ? "com.google.protobuf.ByteString" : "java.lang.String",
ClassName(field->containing_type()), field->index());
}
case FieldDescriptor::CPPTYPE_ENUM:
case FieldDescriptor::CPPTYPE_MESSAGE:
GOOGLE_LOG(FATAL) << "Can't get here.";
return "";
// No default because we want the compiler to complain if any new
// types are added.
}
GOOGLE_LOG(FATAL) << "Can't get here.";
return "";
}
void SetPrimitiveVariables(const FieldDescriptor* descriptor,
map<string, string>* variables) {
(*variables)["name"] =
@ -285,8 +217,17 @@ GenerateBuilderMembers(io::Printer* printer) const {
" return this;\n"
"}\n"
"public Builder clear$capitalized_name$() {\n"
" result.has$capitalized_name$ = false;\n"
" result.$name$_ = $default$;\n"
" result.has$capitalized_name$ = false;\n");
if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
// The default value is not a simple literal so we want to avoid executing
// it multiple times. Instead, get the default out of the default instance.
printer->Print(variables_,
" result.$name$_ = getDefaultInstance().get$capitalized_name$();\n");
} else {
printer->Print(variables_,
" result.$name$_ = $default$;\n");
}
printer->Print(variables_,
" return this;\n"
"}\n");
}
@ -355,7 +296,7 @@ GenerateMembers(io::Printer* printer) const {
"}\n");
if (descriptor_->options().packed() &&
descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
HasGeneratedMethods(descriptor_->containing_type())) {
printer->Print(variables_,
"private int $name$MemoizedSerializedSize;\n");
}

View File

@ -661,7 +661,7 @@ bool Parser::ParseOptionAssignment(Message* options) {
GOOGLE_CHECK(uninterpreted_option_field != NULL)
<< "No field named \"uninterpreted_option\" in the Options proto.";
UninterpretedOption* uninterpreted_option = ::google::protobuf::down_cast<UninterpretedOption*>(
UninterpretedOption* uninterpreted_option = down_cast<UninterpretedOption*>(
options->GetReflection()->AddMessage(options,
uninterpreted_option_field));

View File

@ -798,7 +798,7 @@ namespace {
EncodedDescriptorDatabase* generated_database_ = NULL;
DescriptorPool* generated_pool_ = NULL;
GOOGLE_PROTOBUF_DECLARE_ONCE(generated_pool_init_);
GoogleOnceType generated_pool_init_;
void DeleteGeneratedPool() {
delete generated_database_;
@ -814,7 +814,7 @@ void InitGeneratedPool() {
}
inline void InitGeneratedPoolOnce() {
GoogleOnceInit(&generated_pool_init_, &InitGeneratedPool);
::google::protobuf::GoogleOnceInit(&generated_pool_init_, &InitGeneratedPool);
}
} // anonymous namespace
@ -1859,7 +1859,11 @@ class DescriptorBuilder {
// dependency of this file, it will fail, but will set
// possible_undeclared_dependency_ to point at that file. This is only used
// by AddNotDefinedError() to report a more useful error message.
// possible_undeclared_dependency_name_ is the name of the symbol that was
// actually found in possible_undeclared_dependency_, which may be a parent
// of the symbol actually looked for.
const FileDescriptor* possible_undeclared_dependency_;
string possible_undeclared_dependency_name_;
void AddError(const string& element_name,
const Message& descriptor,
@ -2062,7 +2066,7 @@ class DescriptorBuilder {
Message* options);
// A recursive helper function that drills into the intermediate fields
// in unknown_fields to check if field #field_number is set on the
// in unknown_fields to check if field innermost_field is set on the
// innermost message. Returns false and sets an error if so.
bool ExamineIfOptionIsSet(
vector<const FieldDescriptor*>::const_iterator intermediate_fields_iter,
@ -2233,8 +2237,9 @@ void DescriptorBuilder::AddNotDefinedError(
"\"" + undefined_symbol + "\" is not defined.");
} else {
AddError(element_name, descriptor, location,
"\"" + undefined_symbol + "\" seems to be defined in \""
+ possible_undeclared_dependency_->name() + "\", which is not "
"\"" + possible_undeclared_dependency_name_ +
"\" seems to be defined in \"" +
possible_undeclared_dependency_->name() + "\", which is not "
"imported by \"" + filename_ + "\". To use it here, please "
"add the necessary import.");
}
@ -2295,11 +2300,16 @@ Symbol DescriptorBuilder::FindSymbol(const string& name) {
// symbol unless none of the dependencies define it.
if (IsInPackage(file_, name)) return result;
for (int i = 0; i < file_->dependency_count(); i++) {
if (IsInPackage(file_->dependency(i), name)) return result;
// Note: A dependency may be NULL if it was not found or had errors.
if (file_->dependency(i) != NULL &&
IsInPackage(file_->dependency(i), name)) {
return result;
}
}
}
possible_undeclared_dependency_ = file;
possible_undeclared_dependency_name_ = name;
return kNullSymbol;
}
@ -3592,12 +3602,38 @@ void DescriptorBuilder::CrossLinkMethod(
proto.array_name(i)); \
}
// Determine if the file uses optimize_for = LITE_RUNTIME, being careful to
// avoid problems that exist at init time.
static bool IsLite(const FileDescriptor* file) {
// TODO(kenton): I don't even remember how many of these conditions are
// actually possible. I'm just being super-safe.
return file != NULL &&
&file->options() != NULL &&
&file->options() != &FileOptions::default_instance() &&
file->options().optimize_for() == FileOptions::LITE_RUNTIME;
}
void DescriptorBuilder::ValidateFileOptions(FileDescriptor* file,
const FileDescriptorProto& proto) {
VALIDATE_OPTIONS_FROM_ARRAY(file, message_type, Message);
VALIDATE_OPTIONS_FROM_ARRAY(file, enum_type, Enum);
VALIDATE_OPTIONS_FROM_ARRAY(file, service, Service);
VALIDATE_OPTIONS_FROM_ARRAY(file, extension, Field);
// Lite files can only be imported by other Lite files.
if (!IsLite(file)) {
for (int i = 0; i < file->dependency_count(); i++) {
if (IsLite(file->dependency(i))) {
AddError(
file->name(), proto,
DescriptorPool::ErrorCollector::OTHER,
"Files that do not use optimize_for = LITE_RUNTIME cannot import "
"files which do use this option. This file is not lite, but it "
"imports \"" + file->dependency(i)->name() + "\" which is.");
break;
}
}
}
}
void DescriptorBuilder::ValidateMessageOptions(Descriptor* message,
@ -3647,6 +3683,17 @@ void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field,
"MessageSets cannot have fields, only extensions.");
}
}
// Lite extensions can only be of Lite types.
if (IsLite(field->file()) &&
field->containing_type_ != NULL &&
!IsLite(field->containing_type()->file())) {
AddError(field->full_name(), proto,
DescriptorPool::ErrorCollector::EXTENDEE,
"Extensions to non-lite types can only be declared in non-lite "
"files. Note that you cannot extend a non-lite type to contain "
"a lite type, but the reverse is allowed.");
}
}
void DescriptorBuilder::ValidateEnumOptions(EnumDescriptor* enm,
@ -3660,6 +3707,12 @@ void DescriptorBuilder::ValidateEnumValueOptions(
}
void DescriptorBuilder::ValidateServiceOptions(ServiceDescriptor* service,
const ServiceDescriptorProto& proto) {
if (IsLite(service->file())) {
AddError(service->full_name(), proto,
DescriptorPool::ErrorCollector::NAME,
"Files with optimize_for = LITE_RUNTIME cannot define services.");
}
VALIDATE_OPTIONS_FROM_ARRAY(service, method, Method);
}
@ -3761,7 +3814,7 @@ bool DescriptorBuilder::OptionInterpreter::InterpretOptions(
const int num_uninterpreted_options = original_options->GetReflection()->
FieldSize(*original_options, original_uninterpreted_options_field);
for (int i = 0; i < num_uninterpreted_options; ++i) {
uninterpreted_option_ = ::google::protobuf::down_cast<const UninterpretedOption*>(
uninterpreted_option_ = down_cast<const UninterpretedOption*>(
&original_options->GetReflection()->GetRepeatedMessage(
*original_options, original_uninterpreted_options_field, i));
if (!InterpretSingleOption(options)) {
@ -4009,14 +4062,13 @@ bool DescriptorBuilder::OptionInterpreter::ExamineIfOptionIsSet(
const UnknownField* unknown_field = &unknown_fields.field(i);
FieldDescriptor::Type type = (*intermediate_fields_iter)->type();
// Recurse into the next submessage.
++intermediate_fields_iter;
switch (type) {
case FieldDescriptor::TYPE_MESSAGE:
if (unknown_field->type() == UnknownField::TYPE_LENGTH_DELIMITED) {
UnknownFieldSet intermediate_unknown_fields;
if (intermediate_unknown_fields.ParseFromString(
unknown_field->length_delimited()) &&
!ExamineIfOptionIsSet(intermediate_fields_iter,
!ExamineIfOptionIsSet(intermediate_fields_iter + 1,
intermediate_fields_end,
innermost_field, debug_msg_name,
intermediate_unknown_fields)) {
@ -4027,7 +4079,7 @@ bool DescriptorBuilder::OptionInterpreter::ExamineIfOptionIsSet(
case FieldDescriptor::TYPE_GROUP:
if (unknown_field->type() == UnknownField::TYPE_GROUP) {
if (!ExamineIfOptionIsSet(intermediate_fields_iter,
if (!ExamineIfOptionIsSet(intermediate_fields_iter + 1,
intermediate_fields_end,
innermost_field, debug_msg_name,
unknown_field->group())) {
@ -4139,7 +4191,7 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue(
option_field->full_name() + "\".");
}
unknown_fields->AddFixed32(option_field->number(),
google::protobuf::internal::WireFormat::EncodeFloat(value));
google::protobuf::internal::WireFormatLite::EncodeFloat(value));
break;
}
@ -4156,7 +4208,7 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue(
option_field->full_name() + "\".");
}
unknown_fields->AddFixed64(option_field->number(),
google::protobuf::internal::WireFormat::EncodeDouble(value));
google::protobuf::internal::WireFormatLite::EncodeDouble(value));
break;
}
@ -4267,7 +4319,7 @@ void DescriptorBuilder::OptionInterpreter::SetInt32(int number, int32 value,
case FieldDescriptor::TYPE_SINT32:
unknown_fields->AddVarint(number,
google::protobuf::internal::WireFormat::ZigZagEncode32(value));
google::protobuf::internal::WireFormatLite::ZigZagEncode32(value));
break;
default:
@ -4289,7 +4341,7 @@ void DescriptorBuilder::OptionInterpreter::SetInt64(int number, int64 value,
case FieldDescriptor::TYPE_SINT64:
unknown_fields->AddVarint(number,
google::protobuf::internal::WireFormat::ZigZagEncode64(value));
google::protobuf::internal::WireFormatLite::ZigZagEncode64(value));
break;
default:

File diff suppressed because it is too large Load Diff

View File

@ -18,9 +18,10 @@
#error regenerate this file with a newer version of protoc.
#endif
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/generated_message_reflection.h>
namespace google {
namespace protobuf {
@ -69,11 +70,11 @@ enum FieldDescriptorProto_Type {
FieldDescriptorProto_Type_TYPE_SINT32 = 17,
FieldDescriptorProto_Type_TYPE_SINT64 = 18
};
LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Type_descriptor();
LIBPROTOBUF_EXPORT bool FieldDescriptorProto_Type_IsValid(int value);
const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MIN = FieldDescriptorProto_Type_TYPE_DOUBLE;
const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MAX = FieldDescriptorProto_Type_TYPE_SINT64;
LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Type_descriptor();
inline const ::std::string& FieldDescriptorProto_Type_Name(FieldDescriptorProto_Type value) {
return ::google::protobuf::internal::NameOfEnum(
FieldDescriptorProto_Type_descriptor(), value);
@ -88,11 +89,11 @@ enum FieldDescriptorProto_Label {
FieldDescriptorProto_Label_LABEL_REQUIRED = 2,
FieldDescriptorProto_Label_LABEL_REPEATED = 3
};
LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor();
LIBPROTOBUF_EXPORT bool FieldDescriptorProto_Label_IsValid(int value);
const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MIN = FieldDescriptorProto_Label_LABEL_OPTIONAL;
const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MAX = FieldDescriptorProto_Label_LABEL_REPEATED;
LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor();
inline const ::std::string& FieldDescriptorProto_Label_Name(FieldDescriptorProto_Label value) {
return ::google::protobuf::internal::NameOfEnum(
FieldDescriptorProto_Label_descriptor(), value);
@ -104,13 +105,14 @@ inline bool FieldDescriptorProto_Label_Parse(
}
enum FileOptions_OptimizeMode {
FileOptions_OptimizeMode_SPEED = 1,
FileOptions_OptimizeMode_CODE_SIZE = 2
FileOptions_OptimizeMode_CODE_SIZE = 2,
FileOptions_OptimizeMode_LITE_RUNTIME = 3
};
LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FileOptions_OptimizeMode_descriptor();
LIBPROTOBUF_EXPORT bool FileOptions_OptimizeMode_IsValid(int value);
const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MIN = FileOptions_OptimizeMode_SPEED;
const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = FileOptions_OptimizeMode_CODE_SIZE;
const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = FileOptions_OptimizeMode_LITE_RUNTIME;
LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FileOptions_OptimizeMode_descriptor();
inline const ::std::string& FileOptions_OptimizeMode_Name(FileOptions_OptimizeMode value) {
return ::google::protobuf::internal::NameOfEnum(
FileOptions_OptimizeMode_descriptor(), value);
@ -124,11 +126,11 @@ enum FieldOptions_CType {
FieldOptions_CType_CORD = 1,
FieldOptions_CType_STRING_PIECE = 2
};
LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor();
LIBPROTOBUF_EXPORT bool FieldOptions_CType_IsValid(int value);
const FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_CORD;
const FieldOptions_CType FieldOptions_CType_CType_MAX = FieldOptions_CType_STRING_PIECE;
LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor();
inline const ::std::string& FieldOptions_CType_Name(FieldOptions_CType value) {
return ::google::protobuf::internal::NameOfEnum(
FieldOptions_CType_descriptor(), value);
@ -187,8 +189,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
@ -212,6 +213,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@ -277,8 +279,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
@ -384,6 +385,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(8 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@ -449,8 +451,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
@ -479,6 +480,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@ -544,8 +546,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
@ -635,6 +636,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(7 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@ -700,8 +702,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
@ -724,13 +725,17 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
static const Type TYPE_SFIXED64 = FieldDescriptorProto_Type_TYPE_SFIXED64;
static const Type TYPE_SINT32 = FieldDescriptorProto_Type_TYPE_SINT32;
static const Type TYPE_SINT64 = FieldDescriptorProto_Type_TYPE_SINT64;
static inline bool Type_IsValid(int value) {
return FieldDescriptorProto_Type_IsValid(value);
}
static const Type Type_MIN =
FieldDescriptorProto_Type_Type_MIN;
static const Type Type_MAX =
FieldDescriptorProto_Type_Type_MAX;
static inline const ::google::protobuf::EnumDescriptor*
Type_descriptor() {
return FieldDescriptorProto_Type_descriptor();
}
static inline bool Type_IsValid(int value) {
return FieldDescriptorProto_Type_IsValid(value);
}
static inline const ::std::string& Type_Name(Type value) {
return FieldDescriptorProto_Type_Name(value);
}
@ -738,22 +743,22 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
Type* value) {
return FieldDescriptorProto_Type_Parse(name, value);
}
static const Type Type_MIN =
FieldDescriptorProto_Type_Type_MIN;
static const Type Type_MAX =
FieldDescriptorProto_Type_Type_MAX;
typedef FieldDescriptorProto_Label Label;
static const Label LABEL_OPTIONAL = FieldDescriptorProto_Label_LABEL_OPTIONAL;
static const Label LABEL_REQUIRED = FieldDescriptorProto_Label_LABEL_REQUIRED;
static const Label LABEL_REPEATED = FieldDescriptorProto_Label_LABEL_REPEATED;
static inline bool Label_IsValid(int value) {
return FieldDescriptorProto_Label_IsValid(value);
}
static const Label Label_MIN =
FieldDescriptorProto_Label_Label_MIN;
static const Label Label_MAX =
FieldDescriptorProto_Label_Label_MAX;
static inline const ::google::protobuf::EnumDescriptor*
Label_descriptor() {
return FieldDescriptorProto_Label_descriptor();
}
static inline bool Label_IsValid(int value) {
return FieldDescriptorProto_Label_IsValid(value);
}
static inline const ::std::string& Label_Name(Label value) {
return FieldDescriptorProto_Label_Name(value);
}
@ -761,10 +766,6 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
Label* value) {
return FieldDescriptorProto_Label_Parse(name, value);
}
static const Label Label_MIN =
FieldDescriptorProto_Label_Label_MIN;
static const Label Label_MAX =
FieldDescriptorProto_Label_Label_MAX;
// accessors -------------------------------------------------------
@ -855,6 +856,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(8 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@ -920,8 +922,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
@ -965,6 +966,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@ -1030,8 +1032,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
@ -1072,6 +1073,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@ -1137,8 +1139,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
@ -1182,6 +1183,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@ -1247,8 +1249,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
@ -1305,6 +1306,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(4 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@ -1370,21 +1372,25 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
typedef FileOptions_OptimizeMode OptimizeMode;
static const OptimizeMode SPEED = FileOptions_OptimizeMode_SPEED;
static const OptimizeMode CODE_SIZE = FileOptions_OptimizeMode_CODE_SIZE;
static const OptimizeMode LITE_RUNTIME = FileOptions_OptimizeMode_LITE_RUNTIME;
static inline bool OptimizeMode_IsValid(int value) {
return FileOptions_OptimizeMode_IsValid(value);
}
static const OptimizeMode OptimizeMode_MIN =
FileOptions_OptimizeMode_OptimizeMode_MIN;
static const OptimizeMode OptimizeMode_MAX =
FileOptions_OptimizeMode_OptimizeMode_MAX;
static inline const ::google::protobuf::EnumDescriptor*
OptimizeMode_descriptor() {
return FileOptions_OptimizeMode_descriptor();
}
static inline bool OptimizeMode_IsValid(int value) {
return FileOptions_OptimizeMode_IsValid(value);
}
static inline const ::std::string& OptimizeMode_Name(OptimizeMode value) {
return FileOptions_OptimizeMode_Name(value);
}
@ -1392,10 +1398,6 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
OptimizeMode* value) {
return FileOptions_OptimizeMode_Parse(name, value);
}
static const OptimizeMode OptimizeMode_MIN =
FileOptions_OptimizeMode_OptimizeMode_MIN;
static const OptimizeMode OptimizeMode_MAX =
FileOptions_OptimizeMode_OptimizeMode_MAX;
// accessors -------------------------------------------------------
@ -1459,6 +1461,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(5 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@ -1524,8 +1527,7 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
@ -1538,6 +1540,13 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
inline bool message_set_wire_format() const;
inline void set_message_set_wire_format(bool value);
// optional bool no_standard_descriptor_accessor = 2 [default = false];
inline bool has_no_standard_descriptor_accessor() const;
inline void clear_no_standard_descriptor_accessor();
static const int kNoStandardDescriptorAccessorFieldNumber = 2;
inline bool no_standard_descriptor_accessor() const;
inline void set_no_standard_descriptor_accessor(bool value);
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
inline int uninterpreted_option_size() const;
inline void clear_uninterpreted_option();
@ -1555,11 +1564,13 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
mutable int _cached_size_;
bool message_set_wire_format_;
bool no_standard_descriptor_accessor_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
inline bool _has_bit(int index) const {
@ -1624,21 +1635,24 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
typedef FieldOptions_CType CType;
static const CType CORD = FieldOptions_CType_CORD;
static const CType STRING_PIECE = FieldOptions_CType_STRING_PIECE;
static inline bool CType_IsValid(int value) {
return FieldOptions_CType_IsValid(value);
}
static const CType CType_MIN =
FieldOptions_CType_CType_MIN;
static const CType CType_MAX =
FieldOptions_CType_CType_MAX;
static inline const ::google::protobuf::EnumDescriptor*
CType_descriptor() {
return FieldOptions_CType_descriptor();
}
static inline bool CType_IsValid(int value) {
return FieldOptions_CType_IsValid(value);
}
static inline const ::std::string& CType_Name(CType value) {
return FieldOptions_CType_Name(value);
}
@ -1646,10 +1660,6 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
CType* value) {
return FieldOptions_CType_Parse(name, value);
}
static const CType CType_MIN =
FieldOptions_CType_CType_MIN;
static const CType CType_MAX =
FieldOptions_CType_CType_MAX;
// accessors -------------------------------------------------------
@ -1709,6 +1719,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(5 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@ -1774,8 +1785,7 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message {
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
@ -1801,6 +1811,7 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message {
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@ -1866,8 +1877,7 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message {
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
@ -1893,6 +1903,7 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message {
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@ -1958,8 +1969,7 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message {
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
@ -1985,6 +1995,7 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message {
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@ -2050,8 +2061,7 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message {
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
@ -2077,6 +2087,7 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message {
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@ -2142,8 +2153,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
@ -2176,6 +2186,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@ -2241,8 +2252,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
void SetCachedSize(int size) const { _cached_size_ = size; }
public:
const ::google::protobuf::Descriptor* GetDescriptor() const;
const ::google::protobuf::Reflection* GetReflection() const;
::google::protobuf::Metadata GetMetadata() const;
// nested types ----------------------------------------------------
@ -2316,6 +2326,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag
friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
::google::protobuf::uint32 _has_bits_[(6 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
@ -3647,6 +3658,22 @@ inline void MessageOptions::set_message_set_wire_format(bool value) {
message_set_wire_format_ = value;
}
// optional bool no_standard_descriptor_accessor = 2 [default = false];
inline bool MessageOptions::has_no_standard_descriptor_accessor() const {
return _has_bit(1);
}
inline void MessageOptions::clear_no_standard_descriptor_accessor() {
no_standard_descriptor_accessor_ = false;
_clear_bit(1);
}
inline bool MessageOptions::no_standard_descriptor_accessor() const {
return no_standard_descriptor_accessor_;
}
inline void MessageOptions::set_no_standard_descriptor_accessor(bool value) {
_set_bit(1);
no_standard_descriptor_accessor_ = value;
}
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
inline int MessageOptions::uninterpreted_option_size() const {
return uninterpreted_option_.size();
@ -4134,4 +4161,30 @@ inline ::std::string* UninterpretedOption::mutable_string_value() {
} // namespace protobuf
} // namespace google
#ifndef SWIG
namespace google {
namespace protobuf {
template <>
inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldDescriptorProto_Type>() {
return ::google::protobuf::FieldDescriptorProto_Type_descriptor();
}
template <>
inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldDescriptorProto_Label>() {
return ::google::protobuf::FieldDescriptorProto_Label_descriptor();
}
template <>
inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FileOptions_OptimizeMode>() {
return ::google::protobuf::FileOptions_OptimizeMode_descriptor();
}
template <>
inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldOptions_CType>() {
return ::google::protobuf::FieldOptions_CType_descriptor();
}
} // namespace google
} // namespace protobuf
#endif // SWIG
#endif // PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED

View File

@ -247,8 +247,10 @@ message FileOptions {
// Generated classes can be optimized for speed or code size.
enum OptimizeMode {
SPEED = 1; // Generate complete code for parsing, serialization, etc.
CODE_SIZE = 2; // Use ReflectionOps to implement these methods.
SPEED = 1; // Generate complete code for parsing, serialization,
// etc.
CODE_SIZE = 2; // Use ReflectionOps to implement these methods.
LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.
}
optional OptimizeMode optimize_for = 9 [default=SPEED];
@ -282,6 +284,11 @@ message MessageOptions {
// the protocol compiler.
optional bool message_set_wire_format = 1 [default=false];
// Disables the generation of the standard "descriptor()" accessor, which can
// conflict with a field of the same name. This is meant to make migration
// from proto1 easier; new code should avoid fields named "descriptor".
optional bool no_standard_descriptor_accessor = 2 [default=false];
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;

View File

@ -2135,6 +2135,83 @@ TEST(CustomOptions, OptionsFromOtherFile) {
EXPECT_EQ(FileOptions::SPEED, file->options().optimize_for());
}
TEST(CustomOptions, MessageOptionThreeFieldsSet) {
// This tests a bug which previously existed in custom options parsing. The
// bug occurred when you defined a custom option with message type and then
// set three fields of that option on a single definition (see the example
// below). The bug is a bit hard to explain, so check the change history if
// you want to know more.
DescriptorPool pool;
FileDescriptorProto file_proto;
FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
protobuf_unittest::TestMessageWithCustomOptions::descriptor()
->file()->CopyTo(&file_proto);
ASSERT_TRUE(pool.BuildFile(file_proto) != NULL);
// The following represents the definition:
//
// import "google/protobuf/unittest_custom_options.proto"
// package protobuf_unittest;
// message Foo {
// option (complex_opt1).foo = 1234;
// option (complex_opt1).foo2 = 1234;
// option (complex_opt1).foo3 = 1234;
// }
ASSERT_TRUE(TextFormat::ParseFromString(
"name: \"custom_options_import.proto\" "
"package: \"protobuf_unittest\" "
"dependency: \"google/protobuf/unittest_custom_options.proto\" "
"message_type { "
" name: \"Foo\" "
" options { "
" uninterpreted_option { "
" name { "
" name_part: \"complex_opt1\" "
" is_extension: true "
" } "
" name { "
" name_part: \"foo\" "
" is_extension: false "
" } "
" positive_int_value: 1234 "
" } "
" uninterpreted_option { "
" name { "
" name_part: \"complex_opt1\" "
" is_extension: true "
" } "
" name { "
" name_part: \"foo2\" "
" is_extension: false "
" } "
" positive_int_value: 1234 "
" } "
" uninterpreted_option { "
" name { "
" name_part: \"complex_opt1\" "
" is_extension: true "
" } "
" name { "
" name_part: \"foo3\" "
" is_extension: false "
" } "
" positive_int_value: 1234 "
" } "
" } "
"}",
&file_proto));
const FileDescriptor* file = pool.BuildFile(file_proto);
ASSERT_TRUE(file != NULL);
ASSERT_EQ(1, file->message_type_count());
const MessageOptions& options = file->message_type(0)->options();
EXPECT_EQ(1234, options.GetExtension(protobuf_unittest::complex_opt1).foo());
}
// ===================================================================
@ -2335,6 +2412,30 @@ TEST_F(ValidationErrorTest, UnknownDependency) {
"bar.proto: bar.proto: OTHER: Import \"foo.proto\" has not been loaded.\n");
}
TEST_F(ValidationErrorTest, ForeignUnimportedPackageNoCrash) {
// Used to crash: If we depend on a non-existent file and then refer to a
// package defined in a file that we didn't import, and that package is
// nested within a parent package which this file is also in, and we don't
// include that parent package in the name (i.e. we do a relative lookup)...
// Yes, really.
BuildFile(
"name: 'foo.proto' "
"package: 'outer.foo' ");
BuildFileWithErrors(
"name: 'bar.proto' "
"dependency: 'baz.proto' "
"package: 'outer.bar' "
"message_type { "
" name: 'Bar' "
" field { name:'bar' number:1 label:LABEL_OPTIONAL type_name:'foo.Foo' }"
"}",
"bar.proto: bar.proto: OTHER: Import \"baz.proto\" has not been loaded.\n"
"bar.proto: outer.bar.Bar.bar: TYPE: \"outer.foo\" seems to be defined in "
"\"foo.proto\", which is not imported by \"bar.proto\". To use it here, "
"please add the necessary import.\n");
}
TEST_F(ValidationErrorTest, DupeFile) {
BuildFile(
"name: \"foo.proto\" "
@ -3345,6 +3446,50 @@ TEST_F(ValidationErrorTest, TryingToSetMessageValuedOption) {
"message type.\n");
}
TEST_F(ValidationErrorTest, NotLiteImportsLite) {
BuildFile(
"name: \"bar.proto\" "
"options { optimize_for: LITE_RUNTIME } ");
BuildFileWithErrors(
"name: \"foo.proto\" "
"dependency: \"bar.proto\" ",
"foo.proto: foo.proto: OTHER: Files that do not use optimize_for = "
"LITE_RUNTIME cannot import files which do use this option. This file "
"is not lite, but it imports \"bar.proto\" which is.\n");
}
TEST_F(ValidationErrorTest, LiteExtendsNotLite) {
BuildFile(
"name: \"bar.proto\" "
"message_type: {"
" name: \"Bar\""
" extension_range { start: 1 end: 1000 }"
"}");
BuildFileWithErrors(
"name: \"foo.proto\" "
"dependency: \"bar.proto\" "
"options { optimize_for: LITE_RUNTIME } "
"extension { name: \"ext\" number: 123 label: LABEL_OPTIONAL "
" type: TYPE_INT32 extendee: \"Bar\" }",
"foo.proto: ext: EXTENDEE: Extensions to non-lite types can only be "
"declared in non-lite files. Note that you cannot extend a non-lite "
"type to contain a lite type, but the reverse is allowed.\n");
}
TEST_F(ValidationErrorTest, NoLiteServices) {
BuildFileWithErrors(
"name: \"foo.proto\" "
"options { optimize_for: LITE_RUNTIME } "
"service { name: \"Foo\" }",
"foo.proto: Foo: NAME: Files with optimize_for = LITE_RUNTIME cannot "
"define services.\n");
}
TEST_F(ValidationErrorTest, RollbackAfterError) {
// Build a file which contains every kind of construct but references an
// undefined type. All these constructs will be added to the symbol table

View File

@ -70,6 +70,7 @@
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/repeated_field.h>
@ -82,7 +83,6 @@ namespace protobuf {
using internal::WireFormat;
using internal::ExtensionSet;
using internal::GeneratedMessageReflection;
using internal::GenericRepeatedField;
// ===================================================================
@ -186,8 +186,7 @@ class DynamicMessage : public Message {
int GetCachedSize() const;
void SetCachedSize(int size) const;
const Descriptor* GetDescriptor() const;
const Reflection* GetReflection() const;
Metadata GetMetadata() const;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage);
@ -279,20 +278,10 @@ DynamicMessage::DynamicMessage(const TypeInfo* type_info)
break;
case FieldDescriptor::CPPTYPE_MESSAGE: {
// If this object is the prototype, its CPPTYPE_MESSAGE fields
// must be initialized later, in CrossLinkPrototypes(), so we don't
// initialize them here.
if (!is_prototype()) {
if (!field->is_repeated()) {
new(field_ptr) Message*(NULL);
} else {
const RepeatedPtrField<Message>* prototype_field =
reinterpret_cast<const RepeatedPtrField<Message>*>(
type_info_->prototype->OffsetToPointer(
type_info_->offsets[i]));
new(field_ptr) RepeatedPtrField<Message>(
prototype_field->prototype());
}
if (!field->is_repeated()) {
new(field_ptr) Message*(NULL);
} else {
new(field_ptr) RepeatedPtrField<Message>();
}
break;
}
@ -322,9 +311,33 @@ DynamicMessage::~DynamicMessage() {
void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
if (field->is_repeated()) {
GenericRepeatedField* field =
reinterpret_cast<GenericRepeatedField*>(field_ptr);
field->~GenericRepeatedField();
switch (field->cpp_type()) {
#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
case FieldDescriptor::CPPTYPE_##UPPERCASE : \
reinterpret_cast<RepeatedField<LOWERCASE>*>(field_ptr) \
->~RepeatedField<LOWERCASE>(); \
break
HANDLE_TYPE( INT32, int32);
HANDLE_TYPE( INT64, int64);
HANDLE_TYPE(UINT32, uint32);
HANDLE_TYPE(UINT64, uint64);
HANDLE_TYPE(DOUBLE, double);
HANDLE_TYPE( FLOAT, float);
HANDLE_TYPE( BOOL, bool);
HANDLE_TYPE( ENUM, int);
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING:
reinterpret_cast<RepeatedPtrField<string>*>(field_ptr)
->~RepeatedPtrField<string>();
break;
case FieldDescriptor::CPPTYPE_MESSAGE:
reinterpret_cast<RepeatedPtrField<Message>*>(field_ptr)
->~RepeatedPtrField<Message>();
break;
}
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
string* ptr = *reinterpret_cast<string**>(field_ptr);
@ -353,24 +366,14 @@ void DynamicMessage::CrossLinkPrototypes() {
const FieldDescriptor* field = descriptor->field(i);
void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
!field->is_repeated()) {
// For fields with message types, we need to cross-link with the
// prototype for the field's type.
const Message* field_prototype =
// For singular fields, the field is just a pointer which should
// point to the prototype.
*reinterpret_cast<const Message**>(field_ptr) =
factory->GetPrototype(field->message_type());
if (field->is_repeated()) {
// For repeated fields, we actually construct the RepeatedPtrField
// here, but only for fields with message types. All other repeated
// fields are constructed in DynamicMessage's constructor.
new(field_ptr) RepeatedPtrField<Message>(field_prototype);
} else {
// For singular fields, the field is just a pointer which should
// point to the prototype. (OK to const_cast here because the
// prototype itself will only be available const to the outside
// world.)
new(field_ptr) Message*(const_cast<Message*>(field_prototype));
}
}
}
}
@ -392,12 +395,11 @@ void DynamicMessage::SetCachedSize(int size) const {
cached_byte_size_ = size;
}
const Descriptor* DynamicMessage::GetDescriptor() const {
return type_info_->type;
}
const Reflection* DynamicMessage::GetReflection() const {
return type_info_->reflection.get();
Metadata DynamicMessage::GetMetadata() const {
Metadata metadata;
metadata.descriptor = type_info_->type;
metadata.reflection = type_info_->reflection.get();
return metadata;
}
// ===================================================================

File diff suppressed because it is too large Load Diff

View File

@ -45,20 +45,23 @@
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/message.h>
namespace google {
namespace protobuf {
class Descriptor; // descriptor.h
class FieldDescriptor; // descriptor.h
class DescriptorPool; // descriptor.h
class Message; // message.h
class MessageLite; // message_lite.h
class MessageFactory; // message.h
class UnknownFieldSet; // unknown_field_set.h
namespace io {
class CodedInputStream; // coded_stream.h
class CodedOutputStream; // coded_stream.h
}
namespace internal {
class FieldSkipper; // wire_format_lite.h
}
template <typename Element> class RepeatedField; // repeated_field.h
template <typename Element> class RepeatedPtrField; // repeated_field.h
}
@ -66,9 +69,9 @@ namespace protobuf {
namespace protobuf {
namespace internal {
// Used to store values of type FieldDescriptor::Type without having to
// #include descriptor.h. Also, ensures that we use only one byte to store
// these values, which is important to keep the layout of
// Used to store values of type WireFormatLite::FieldType without having to
// #include wire_format_lite.h. Also, ensures that we use only one byte to
// store these values, which is important to keep the layout of
// ExtensionSet::Extension small.
typedef uint8 FieldType;
@ -98,17 +101,17 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
// to look up extensions for parsed field numbers. Note that dynamic parsing
// does not use ParseField(); only protocol-compiler-generated parsing
// methods do.
static void RegisterExtension(const Message* containing_type,
static void RegisterExtension(const MessageLite* containing_type,
int number, FieldType type,
bool is_repeated, bool is_packed);
static void RegisterEnumExtension(const Message* containing_type,
static void RegisterEnumExtension(const MessageLite* containing_type,
int number, FieldType type,
bool is_repeated, bool is_packed,
EnumValidityFunc* is_valid);
static void RegisterMessageExtension(const Message* containing_type,
static void RegisterMessageExtension(const MessageLite* containing_type,
int number, FieldType type,
bool is_repeated, bool is_packed,
const Message* prototype);
const MessageLite* prototype);
// =================================================================
@ -167,9 +170,10 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
bool GetBool (int number, bool default_value) const;
int GetEnum (int number, int default_value) const;
const string & GetString (int number, const string& default_value) const;
const Message& GetMessage(int number, const Message& default_value) const;
const Message& GetMessage(int number, const Descriptor* message_type,
MessageFactory* factory) const;
const MessageLite& GetMessage(int number,
const MessageLite& default_value) const;
const MessageLite& GetMessage(int number, const Descriptor* message_type,
MessageFactory* factory) const;
void SetInt32 (int number, FieldType type, int32 value);
void SetInt64 (int number, FieldType type, int64 value);
@ -181,11 +185,11 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
void SetEnum (int number, FieldType type, int value);
void SetString(int number, FieldType type, const string& value);
string * MutableString (int number, FieldType type);
Message* MutableMessage(int number, FieldType type,
const Message& prototype);
Message* MutableMessage(int number, FieldType type,
const Descriptor* message_type,
MessageFactory* factory);
MessageLite* MutableMessage(int number, FieldType type,
const MessageLite& prototype);
MessageLite* MutableMessage(int number, FieldType type,
const Descriptor* message_type,
MessageFactory* factory);
// repeated fields -------------------------------------------------
@ -198,7 +202,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
bool GetRepeatedBool (int number, int index) const;
int GetRepeatedEnum (int number, int index) const;
const string & GetRepeatedString (int number, int index) const;
const Message& GetRepeatedMessage(int number, int index) const;
const MessageLite& GetRepeatedMessage(int number, int index) const;
void SetRepeatedInt32 (int number, int index, int32 value);
void SetRepeatedInt64 (int number, int index, int64 value);
@ -210,7 +214,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
void SetRepeatedEnum (int number, int index, int value);
void SetRepeatedString(int number, int index, const string& value);
string * MutableRepeatedString (int number, int index);
Message* MutableRepeatedMessage(int number, int index);
MessageLite* MutableRepeatedMessage(int number, int index);
void AddInt32 (int number, FieldType type, bool packed, int32 value);
void AddInt64 (int number, FieldType type, bool packed, int64 value);
@ -222,11 +226,11 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
void AddEnum (int number, FieldType type, bool packed, int value);
void AddString(int number, FieldType type, const string& value);
string * AddString (int number, FieldType type);
Message* AddMessage(int number, FieldType type,
const Message& prototype);
Message* AddMessage(int number, FieldType type,
const Descriptor* message_type,
MessageFactory* factory);
MessageLite* AddMessage(int number, FieldType type,
const MessageLite& prototype);
MessageLite* AddMessage(int number, FieldType type,
const Descriptor* message_type,
MessageFactory* factory);
void RemoveLast(int number);
void SwapElements(int number, int index1, int index2);
@ -252,9 +256,31 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
// methods of ExtensionSet, this only works for generated message types --
// it looks up extensions registered using RegisterExtension().
bool ParseField(uint32 tag, io::CodedInputStream* input,
const Message* containing_type,
const MessageLite* containing_type,
FieldSkipper* field_skipper);
// Specific versions for lite or full messages (constructs the appropriate
// FieldSkipper automatically).
bool ParseField(uint32 tag, io::CodedInputStream* input,
const MessageLite* containing_type);
bool ParseField(uint32 tag, io::CodedInputStream* input,
const MessageLite* containing_type,
UnknownFieldSet* unknown_fields);
// Parse an entire message in MessageSet format. Such messages have no
// fields, only extensions.
bool ParseMessageSet(io::CodedInputStream* input,
const MessageLite* containing_type,
FieldSkipper* field_skipper);
// Specific versions for lite or full messages (constructs the appropriate
// FieldSkipper automatically).
bool ParseMessageSet(io::CodedInputStream* input,
const MessageLite* containing_type);
bool ParseMessageSet(io::CodedInputStream* input,
const MessageLite* containing_type,
UnknownFieldSet* unknown_fields);
// Write all extension fields with field numbers in the range
// [start_field_number, end_field_number)
// to the output stream, using the cached sizes computed when ByteSize() was
@ -272,37 +298,50 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
int end_field_number,
uint8* target) const;
// Like above but serializes in MessageSet format.
void SerializeMessageSetWithCachedSizes(io::CodedOutputStream* output) const;
uint8* SerializeMessageSetWithCachedSizesToArray(uint8* target) const;
// Returns the total serialized size of all the extensions.
int ByteSize() const;
// Like ByteSize() but uses MessageSet format.
int MessageSetByteSize() const;
// Returns (an estimate of) the total number of bytes used for storing the
// extensions in memory, excluding sizeof(*this).
// extensions in memory, excluding sizeof(*this). If the ExtensionSet is
// for a lite message (and thus possibly contains lite messages), the results
// are undefined (might work, might crash, might corrupt data, might not even
// be linked in). It's up to the protocol compiler to avoid calling this on
// such ExtensionSets (easy enough since lite messages don't implement
// SpaceUsed()).
int SpaceUsedExcludingSelf() const;
private:
struct Extension {
union {
int32 int32_value;
int64 int64_value;
uint32 uint32_value;
uint64 uint64_value;
float float_value;
double double_value;
bool bool_value;
int enum_value;
string* string_value;
Message* message_value;
int32 int32_value;
int64 int64_value;
uint32 uint32_value;
uint64 uint64_value;
float float_value;
double double_value;
bool bool_value;
int enum_value;
string* string_value;
MessageLite* message_value;
RepeatedField <int32 >* repeated_int32_value;
RepeatedField <int64 >* repeated_int64_value;
RepeatedField <uint32 >* repeated_uint32_value;
RepeatedField <uint64 >* repeated_uint64_value;
RepeatedField <float >* repeated_float_value;
RepeatedField <double >* repeated_double_value;
RepeatedField <bool >* repeated_bool_value;
RepeatedField <int >* repeated_enum_value;
RepeatedPtrField<string >* repeated_string_value;
RepeatedPtrField<Message>* repeated_message_value;
RepeatedField <int32 >* repeated_int32_value;
RepeatedField <int64 >* repeated_int64_value;
RepeatedField <uint32 >* repeated_uint32_value;
RepeatedField <uint64 >* repeated_uint64_value;
RepeatedField <float >* repeated_float_value;
RepeatedField <double >* repeated_double_value;
RepeatedField <bool >* repeated_bool_value;
RepeatedField <int >* repeated_enum_value;
RepeatedPtrField<string >* repeated_string_value;
RepeatedPtrField<MessageLite>* repeated_message_value;
};
FieldType type;
@ -328,7 +367,11 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
void SerializeFieldWithCachedSizes(
int number,
io::CodedOutputStream* output) const;
void SerializeMessageSetItemWithCachedSizes(
int number,
io::CodedOutputStream* output) const;
int ByteSize(int number) const;
int MessageSetItemByteSize(int number) const;
void Clear();
int GetSize() const;
void Free();
@ -339,6 +382,13 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
// already exist. Returns true if the extension did not already exist.
bool MaybeNewExtension(int number, Extension** result);
// Parse a single MessageSet item -- called just after the item group start
// tag has been read.
bool ParseMessageSetItem(io::CodedInputStream* input,
const MessageLite* containing_type,
FieldSkipper* field_skipper);
// The Extension struct is small enough to be passed by value, so we use it
// directly as the value type in the map rather than use pointers. We use
// a map rather than hash_map here because we expect most ExtensionSets will

View File

@ -0,0 +1,218 @@
// 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: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
//
// Contains methods defined in extension_set.h which cannot be part of the
// lite library because they use descriptors or reflection.
#include <google/protobuf/extension_set.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format.h>
namespace google {
namespace protobuf {
namespace internal {
void ExtensionSet::AppendToList(const Descriptor* containing_type,
const DescriptorPool* pool,
vector<const FieldDescriptor*>* output) const {
for (map<int, Extension>::const_iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
bool has = false;
if (iter->second.is_repeated) {
has = iter->second.GetSize() > 0;
} else {
has = !iter->second.is_cleared;
}
if (has) {
output->push_back(
pool->FindExtensionByNumber(containing_type, iter->first));
}
}
}
inline FieldDescriptor::CppType cpp_type(FieldType type) {
return FieldDescriptor::TypeToCppType(
static_cast<FieldDescriptor::Type>(type));
}
#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \
GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED \
: FieldDescriptor::LABEL_OPTIONAL, \
FieldDescriptor::LABEL_##LABEL); \
GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), FieldDescriptor::CPPTYPE_##CPPTYPE)
const MessageLite& ExtensionSet::GetMessage(int number,
const Descriptor* message_type,
MessageFactory* factory) const {
map<int, Extension>::const_iterator iter = extensions_.find(number);
if (iter == extensions_.end() || iter->second.is_cleared) {
// Not present. Return the default value.
return *factory->GetPrototype(message_type);
} else {
GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
return *iter->second.message_value;
}
}
MessageLite* ExtensionSet::MutableMessage(int number, FieldType type,
const Descriptor* message_type,
MessageFactory* factory) {
Extension* extension;
if (MaybeNewExtension(number, &extension)) {
extension->type = type;
GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
extension->is_repeated = false;
extension->is_packed = false;
const MessageLite* prototype = factory->GetPrototype(message_type);
GOOGLE_CHECK(prototype != NULL);
extension->message_value = prototype->New();
} else {
GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
}
extension->is_cleared = false;
return extension->message_value;
}
MessageLite* ExtensionSet::AddMessage(int number, FieldType type,
const Descriptor* message_type,
MessageFactory* factory) {
Extension* extension;
if (MaybeNewExtension(number, &extension)) {
extension->type = type;
GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
extension->is_repeated = true;
extension->repeated_message_value =
new RepeatedPtrField<MessageLite>();
} else {
GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
}
// RepeatedPtrField<Message> does not know how to Add() since it cannot
// allocate an abstract object, so we have to be tricky.
MessageLite* result = extension->repeated_message_value
->AddFromCleared<internal::GenericTypeHandler<MessageLite> >();
if (result == NULL) {
const MessageLite* prototype;
if (extension->repeated_message_value->size() == 0) {
prototype = factory->GetPrototype(message_type);
GOOGLE_CHECK(prototype != NULL);
} else {
prototype = &extension->repeated_message_value->Get(0);
}
result = prototype->New();
extension->repeated_message_value->AddAllocated(result);
}
return result;
}
bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
const MessageLite* containing_type,
UnknownFieldSet* unknown_fields) {
UnknownFieldSetFieldSkipper skipper(unknown_fields);
return ParseField(tag, input, containing_type, &skipper);
}
bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
const MessageLite* containing_type,
UnknownFieldSet* unknown_fields) {
UnknownFieldSetFieldSkipper skipper(unknown_fields);
return ParseMessageSet(input, containing_type, &skipper);
}
int ExtensionSet::SpaceUsedExcludingSelf() const {
int total_size =
extensions_.size() * sizeof(map<int, Extension>::value_type);
for (map<int, Extension>::const_iterator iter = extensions_.begin(),
end = extensions_.end();
iter != end;
++iter) {
total_size += iter->second.SpaceUsedExcludingSelf();
}
return total_size;
}
int ExtensionSet::Extension::SpaceUsedExcludingSelf() const {
int total_size = 0;
if (is_repeated) {
switch (cpp_type(type)) {
#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
case WireFormatLite::CPPTYPE_##UPPERCASE: \
total_size += sizeof(*repeated_##LOWERCASE##_value) + \
repeated_##LOWERCASE##_value->SpaceUsedExcludingSelf();\
break
HANDLE_TYPE( INT32, int32);
HANDLE_TYPE( INT64, int64);
HANDLE_TYPE( UINT32, uint32);
HANDLE_TYPE( UINT64, uint64);
HANDLE_TYPE( FLOAT, float);
HANDLE_TYPE( DOUBLE, double);
HANDLE_TYPE( BOOL, bool);
HANDLE_TYPE( ENUM, enum);
HANDLE_TYPE( STRING, string);
case WireFormatLite::CPPTYPE_MESSAGE:
// repeated_message_value is actually a RepeatedPtrField<MessageLite>,
// but MessageLite has no SpaceUsed(), so we must directly call
// RepeatedPtrFieldBase::SpaceUsedExcludingSelf() with a different type
// handler.
total_size += sizeof(*repeated_message_value) +
repeated_message_value->
RepeatedPtrFieldBase::SpaceUsedExcludingSelf<
GenericTypeHandler<Message> >();
break;
}
} else {
switch (cpp_type(type)) {
case WireFormatLite::CPPTYPE_STRING:
total_size += sizeof(*string_value) +
StringSpaceUsedExcludingSelf(*string_value);
break;
case WireFormatLite::CPPTYPE_MESSAGE:
total_size += down_cast<Message*>(message_value)->SpaceUsed();
break;
default:
// No extra storage costs for primitive types.
break;
}
}
return total_size;
}
} // namespace internal
} // namespace protobuf
} // namespace google

View File

@ -38,6 +38,7 @@
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/stubs/common.h>
namespace google {
@ -220,8 +221,36 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const {
const FieldDescriptor* field = descriptor_->field(i);
if (field->is_repeated()) {
total_size += GetRaw<GenericRepeatedField>(message, field)
.GenericSpaceUsedExcludingSelf();
switch (field->cpp_type()) {
#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
case FieldDescriptor::CPPTYPE_##UPPERCASE : \
total_size += GetRaw<RepeatedField<LOWERCASE> >(message, field) \
.SpaceUsedExcludingSelf(); \
break
HANDLE_TYPE( INT32, int32);
HANDLE_TYPE( INT64, int64);
HANDLE_TYPE(UINT32, uint32);
HANDLE_TYPE(UINT64, uint64);
HANDLE_TYPE(DOUBLE, double);
HANDLE_TYPE( FLOAT, float);
HANDLE_TYPE( BOOL, bool);
HANDLE_TYPE( ENUM, int);
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING:
total_size += GetRaw<RepeatedPtrField<string> >(message, field)
.SpaceUsedExcludingSelf();
break;
case FieldDescriptor::CPPTYPE_MESSAGE:
// We don't know which subclass of RepeatedPtrFieldBase the type is,
// so we use RepeatedPtrFieldBase directly.
total_size +=
GetRaw<RepeatedPtrFieldBase>(message, field)
.SpaceUsedExcludingSelf<GenericTypeHandler<Message> >();
break;
}
} else {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32 :
@ -274,25 +303,59 @@ void GeneratedMessageReflection::Swap(
Message* message2) const {
if (message1 == message2) return;
// TODO(kenton): Other Reflection methods should probably check this too.
GOOGLE_CHECK_EQ(message1->GetReflection(), this)
<< "Tried to swap using reflection object incompatible with message1.";
<< "First argument to Swap() (of type \""
<< message1->GetDescriptor()->full_name()
<< "\") is not compatible with this reflection object (which is for type \""
<< descriptor_->full_name()
<< "\"). Note that the exact same class is required; not just the same "
"descriptor.";
GOOGLE_CHECK_EQ(message2->GetReflection(), this)
<< "Tried to swap using reflection object incompatible with message2.";
<< "Second argument to Swap() (of type \""
<< message1->GetDescriptor()->full_name()
<< "\") is not compatible with this reflection object (which is for type \""
<< descriptor_->full_name()
<< "\"). Note that the exact same class is required; not just the same "
"descriptor.";
uint32* has_bits1 = MutableHasBits(message1);
uint32* has_bits2 = MutableHasBits(message2);
int has_bits_size = (descriptor_->field_count() + 31) / 32;
for (int i = 0; i < has_bits_size; i++) {
std::swap(has_bits1[i], has_bits2[i]);
swap(has_bits1[i], has_bits2[i]);
}
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
if (field->is_repeated()) {
MutableRaw<GenericRepeatedField>(message1, field)->GenericSwap(
MutableRaw<GenericRepeatedField>(message2, field));
switch (field->cpp_type()) {
#define SWAP_ARRAYS(CPPTYPE, TYPE) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
MutableRaw<RepeatedField<TYPE> >(message1, field)->Swap( \
MutableRaw<RepeatedField<TYPE> >(message2, field)); \
break;
SWAP_ARRAYS(INT32 , int32 );
SWAP_ARRAYS(INT64 , int64 );
SWAP_ARRAYS(UINT32, uint32);
SWAP_ARRAYS(UINT64, uint64);
SWAP_ARRAYS(FLOAT , float );
SWAP_ARRAYS(DOUBLE, double);
SWAP_ARRAYS(BOOL , bool );
SWAP_ARRAYS(ENUM , int );
#undef SWAP_ARRAYS
case FieldDescriptor::CPPTYPE_STRING:
case FieldDescriptor::CPPTYPE_MESSAGE:
MutableRaw<RepeatedPtrFieldBase>(message1, field)->Swap(
MutableRaw<RepeatedPtrFieldBase>(message2, field));
break;
default:
GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type();
}
} else {
switch (field->cpp_type()) {
#define SWAP_VALUES(CPPTYPE, TYPE) \
@ -300,6 +363,7 @@ void GeneratedMessageReflection::Swap(
swap(*MutableRaw<TYPE>(message1, field), \
*MutableRaw<TYPE>(message2, field)); \
break;
SWAP_VALUES(INT32 , int32 );
SWAP_VALUES(INT64 , int64 );
SWAP_VALUES(UINT32, uint32);
@ -307,10 +371,15 @@ void GeneratedMessageReflection::Swap(
SWAP_VALUES(FLOAT , float );
SWAP_VALUES(DOUBLE, double);
SWAP_VALUES(BOOL , bool );
SWAP_VALUES(ENUM , int32 );
SWAP_VALUES(STRING, string*);
SWAP_VALUES(ENUM , int );
SWAP_VALUES(MESSAGE, Message*);
#undef SWAP_PRIMITIVE_VALUES
#undef SWAP_VALUES
case FieldDescriptor::CPPTYPE_STRING:
swap(*MutableRaw<string*>(message1, field),
*MutableRaw<string*>(message2, field));
break;
default:
GOOGLE_LOG(FATAL) << "Unimplemented type: " << field->cpp_type();
}
@ -346,7 +415,28 @@ int GeneratedMessageReflection::FieldSize(const Message& message,
if (field->is_extension()) {
return GetExtensionSet(message).ExtensionSize(field->number());
} else {
return GetRaw<GenericRepeatedField>(message, field).GenericSize();
switch (field->cpp_type()) {
#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
case FieldDescriptor::CPPTYPE_##UPPERCASE : \
return GetRaw<RepeatedField<LOWERCASE> >(message, field).size()
HANDLE_TYPE( INT32, int32);
HANDLE_TYPE( INT64, int64);
HANDLE_TYPE(UINT32, uint32);
HANDLE_TYPE(UINT64, uint64);
HANDLE_TYPE(DOUBLE, double);
HANDLE_TYPE( FLOAT, float);
HANDLE_TYPE( BOOL, bool);
HANDLE_TYPE( ENUM, int);
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING:
case FieldDescriptor::CPPTYPE_MESSAGE:
return GetRaw<RepeatedPtrFieldBase>(message, field).size();
}
GOOGLE_LOG(FATAL) << "Can't get here.";
return 0;
}
}
@ -401,7 +491,35 @@ void GeneratedMessageReflection::ClearField(
}
}
} else {
MutableRaw<GenericRepeatedField>(message, field)->GenericClear();
switch (field->cpp_type()) {
#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
case FieldDescriptor::CPPTYPE_##UPPERCASE : \
MutableRaw<RepeatedField<LOWERCASE> >(message, field)->Clear(); \
break
HANDLE_TYPE( INT32, int32);
HANDLE_TYPE( INT64, int64);
HANDLE_TYPE(UINT32, uint32);
HANDLE_TYPE(UINT64, uint64);
HANDLE_TYPE(DOUBLE, double);
HANDLE_TYPE( FLOAT, float);
HANDLE_TYPE( BOOL, bool);
HANDLE_TYPE( ENUM, int);
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING: {
MutableRaw<RepeatedPtrField<string> >(message, field)->Clear();
break;
}
case FieldDescriptor::CPPTYPE_MESSAGE: {
// We don't know which subclass of RepeatedPtrFieldBase the type is,
// so we use RepeatedPtrFieldBase directly.
MutableRaw<RepeatedPtrFieldBase>(message, field)
->Clear<GenericTypeHandler<Message> >();
break;
}
}
}
}
@ -414,7 +532,31 @@ void GeneratedMessageReflection::RemoveLast(
if (field->is_extension()) {
MutableExtensionSet(message)->RemoveLast(field->number());
} else {
MutableRaw<GenericRepeatedField>(message, field)->GenericRemoveLast();
switch (field->cpp_type()) {
#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
case FieldDescriptor::CPPTYPE_##UPPERCASE : \
MutableRaw<RepeatedField<LOWERCASE> >(message, field)->RemoveLast(); \
break
HANDLE_TYPE( INT32, int32);
HANDLE_TYPE( INT64, int64);
HANDLE_TYPE(UINT32, uint32);
HANDLE_TYPE(UINT64, uint64);
HANDLE_TYPE(DOUBLE, double);
HANDLE_TYPE( FLOAT, float);
HANDLE_TYPE( BOOL, bool);
HANDLE_TYPE( ENUM, int);
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING:
MutableRaw<RepeatedPtrField<string> >(message, field)->RemoveLast();
break;
case FieldDescriptor::CPPTYPE_MESSAGE:
MutableRaw<RepeatedPtrFieldBase>(message, field)
->RemoveLast<GenericTypeHandler<Message> >();
break;
}
}
}
@ -427,11 +569,31 @@ void GeneratedMessageReflection::SwapElements(
USAGE_CHECK_REPEATED(Swap);
if (field->is_extension()) {
MutableExtensionSet(message)->SwapElements(
field->number(), index1, index2);
MutableExtensionSet(message)->SwapElements(field->number(), index1, index2);
} else {
MutableRaw<GenericRepeatedField>(message, field)->GenericSwapElements(
index1, index2);
switch (field->cpp_type()) {
#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
case FieldDescriptor::CPPTYPE_##UPPERCASE : \
MutableRaw<RepeatedField<LOWERCASE> >(message, field) \
->SwapElements(index1, index2); \
break
HANDLE_TYPE( INT32, int32);
HANDLE_TYPE( INT64, int64);
HANDLE_TYPE(UINT32, uint32);
HANDLE_TYPE(UINT64, uint64);
HANDLE_TYPE(DOUBLE, double);
HANDLE_TYPE( FLOAT, float);
HANDLE_TYPE( BOOL, bool);
HANDLE_TYPE( ENUM, int);
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING:
case FieldDescriptor::CPPTYPE_MESSAGE:
MutableRaw<RepeatedPtrFieldBase>(message, field)
->SwapElements(index1, index2);
break;
}
}
}
@ -456,7 +618,7 @@ void GeneratedMessageReflection::ListFields(
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
if (field->is_repeated()) {
if (GetRaw<GenericRepeatedField>(message, field).GenericSize() > 0) {
if (FieldSize(message, field) > 0) {
output->push_back(field);
}
} else {
@ -597,7 +759,7 @@ string GeneratedMessageReflection::GetRepeatedString(
if (field->is_extension()) {
return GetExtensionSet(message).GetRepeatedString(field->number(), index);
} else {
return GetRepeatedField<string>(message, field, index);
return GetRepeatedPtrField<string>(message, field, index);
}
}
@ -608,7 +770,7 @@ const string& GeneratedMessageReflection::GetRepeatedStringReference(
if (field->is_extension()) {
return GetExtensionSet(message).GetRepeatedString(field->number(), index);
} else {
return GetRepeatedField<string>(message, field, index);
return GetRepeatedPtrField<string>(message, field, index);
}
}
@ -621,7 +783,7 @@ void GeneratedMessageReflection::SetRepeatedString(
MutableExtensionSet(message)->SetRepeatedString(
field->number(), index, value);
} else {
SetRepeatedField<string>(message, field, index, value);
*MutableRepeatedField<string>(message, field, index) = value;
}
}
@ -634,7 +796,7 @@ void GeneratedMessageReflection::AddString(
MutableExtensionSet(message)->AddString(field->number(),
field->type(), value);
} else {
AddField<string>(message, field, value);
*AddField<string>(message, field) = value;
}
}
@ -725,9 +887,10 @@ const Message& GeneratedMessageReflection::GetMessage(
USAGE_CHECK_ALL(GetMessage, SINGULAR, MESSAGE);
if (field->is_extension()) {
return GetExtensionSet(message).GetMessage(field->number(),
field->message_type(),
message_factory_);
return static_cast<const Message&>(
GetExtensionSet(message).GetMessage(field->number(),
field->message_type(),
message_factory_));
} else {
const Message* result = GetRaw<const Message*>(message, field);
if (result == NULL) {
@ -742,10 +905,11 @@ Message* GeneratedMessageReflection::MutableMessage(
USAGE_CHECK_ALL(MutableMessage, SINGULAR, MESSAGE);
if (field->is_extension()) {
return MutableExtensionSet(message)->MutableMessage(field->number(),
field->type(),
field->message_type(),
message_factory_);
return static_cast<Message*>(
MutableExtensionSet(message)->MutableMessage(field->number(),
field->type(),
field->message_type(),
message_factory_));
} else {
Message** result = MutableField<Message*>(message, field);
if (*result == NULL) {
@ -761,9 +925,11 @@ const Message& GeneratedMessageReflection::GetRepeatedMessage(
USAGE_CHECK_ALL(GetRepeatedMessage, REPEATED, MESSAGE);
if (field->is_extension()) {
return GetExtensionSet(message).GetRepeatedMessage(field->number(), index);
return static_cast<const Message&>(
GetExtensionSet(message).GetRepeatedMessage(field->number(), index));
} else {
return GetRepeatedField<Message>(message, field, index);
return GetRaw<RepeatedPtrFieldBase>(message, field)
.Get<GenericTypeHandler<Message> >(index);
}
}
@ -772,10 +938,12 @@ Message* GeneratedMessageReflection::MutableRepeatedMessage(
USAGE_CHECK_ALL(MutableRepeatedMessage, REPEATED, MESSAGE);
if (field->is_extension()) {
return MutableExtensionSet(message)->MutableRepeatedMessage(
field->number(), index);
return static_cast<Message*>(
MutableExtensionSet(message)->MutableRepeatedMessage(
field->number(), index));
} else {
return MutableRepeatedField<Message>(message, field, index);
return MutableRaw<RepeatedPtrFieldBase>(message, field)
->Mutable<GenericTypeHandler<Message> >(index);
}
}
@ -784,12 +952,29 @@ Message* GeneratedMessageReflection::AddMessage(
USAGE_CHECK_ALL(AddMessage, REPEATED, MESSAGE);
if (field->is_extension()) {
return MutableExtensionSet(message)->AddMessage(field->number(),
field->type(),
field->message_type(),
message_factory_);
return static_cast<Message*>(
MutableExtensionSet(message)->AddMessage(field->number(),
field->type(),
field->message_type(),
message_factory_));
} else {
return AddField<Message>(message, field);
// We can't use AddField<Message>() because RepeatedPtrFieldBase doesn't
// know how to allocate one.
RepeatedPtrFieldBase* repeated =
MutableRaw<RepeatedPtrFieldBase>(message, field);
Message* result = repeated->AddFromCleared<GenericTypeHandler<Message> >();
if (result == NULL) {
// We must allocate a new object.
const Message* prototype;
if (repeated->size() == 0) {
prototype = message_factory_->GetPrototype(field->message_type());
} else {
prototype = &repeated->Get<GenericTypeHandler<Message> >(0);
}
result = prototype->New();
repeated->AddAllocated<GenericTypeHandler<Message> >(result);
}
return result;
}
}
@ -925,46 +1110,46 @@ inline Type* GeneratedMessageReflection::MutableField(
}
template <typename Type>
inline const Type& GeneratedMessageReflection::GetRepeatedField(
inline Type GeneratedMessageReflection::GetRepeatedField(
const Message& message, const FieldDescriptor* field, int index) const {
return *reinterpret_cast<const Type*>(
GetRaw<GenericRepeatedField>(message, field).GenericGet(index));
return GetRaw<RepeatedField<Type> >(message, field).Get(index);
}
template <typename Type>
inline const Type& GeneratedMessageReflection::GetRepeatedPtrField(
const Message& message, const FieldDescriptor* field, int index) const {
return GetRaw<RepeatedPtrField<Type> >(message, field).Get(index);
}
template <typename Type>
inline void GeneratedMessageReflection::SetRepeatedField(
Message* message, const FieldDescriptor* field,
int index, const Type& value) const {
GenericRepeatedField* repeated =
MutableRaw<GenericRepeatedField>(message, field);
*reinterpret_cast<Type*>(repeated->GenericMutable(index)) = value;
int index, Type value) const {
MutableRaw<RepeatedField<Type> >(message, field)->Set(index, value);
}
template <typename Type>
inline Type* GeneratedMessageReflection::MutableRepeatedField(
Message* message, const FieldDescriptor* field, int index) const {
GenericRepeatedField* repeated =
MutableRaw<GenericRepeatedField>(message, field);
return reinterpret_cast<Type*>(repeated->GenericMutable(index));
RepeatedPtrField<Type>* repeated =
MutableRaw<RepeatedPtrField<Type> >(message, field);
return repeated->Mutable(index);
}
template <typename Type>
inline void GeneratedMessageReflection::AddField(
Message* message, const FieldDescriptor* field, const Type& value) const {
GenericRepeatedField* repeated =
MutableRaw<GenericRepeatedField>(message, field);
*reinterpret_cast<Type*>(repeated->GenericAdd()) = value;
Message* message, const FieldDescriptor* field, Type value) const {
MutableRaw<RepeatedField<Type> >(message, field)->Add(value);
}
template <typename Type>
inline Type* GeneratedMessageReflection::AddField(
Message* message, const FieldDescriptor* field) const {
GenericRepeatedField* repeated =
MutableRaw<GenericRepeatedField>(message, field);
return reinterpret_cast<Type*>(repeated->GenericAdd());
RepeatedPtrField<Type>* repeated =
MutableRaw<RepeatedPtrField<Type> >(message, field);
return repeated->Add();
}
} // namespace internal
} // namespace protobuf
} // namespace google

View File

@ -142,7 +142,7 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection {
void ClearField(Message* message, const FieldDescriptor* field) const;
void RemoveLast(Message* message, const FieldDescriptor* field) const;
void Swap(Message* message1, Message* message2) const;
void SwapElements(Message* message, const FieldDescriptor* field,
void SwapElements(Message* message, const FieldDescriptor* field,
int index1, int index2) const;
void ListFields(const Message& message,
vector<const FieldDescriptor*>* output) const;
@ -314,20 +314,24 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection {
inline Type* MutableField(Message* message,
const FieldDescriptor* field) const;
template <typename Type>
inline const Type& GetRepeatedField(const Message& message,
const FieldDescriptor* field,
int index) const;
inline Type GetRepeatedField(const Message& message,
const FieldDescriptor* field,
int index) const;
template <typename Type>
inline const Type& GetRepeatedPtrField(const Message& message,
const FieldDescriptor* field,
int index) const;
template <typename Type>
inline void SetRepeatedField(Message* message,
const FieldDescriptor* field, int index,
const Type& value) const;
Type value) const;
template <typename Type>
inline Type* MutableRepeatedField(Message* message,
const FieldDescriptor* field,
int index) const;
template <typename Type>
inline void AddField(Message* message,
const FieldDescriptor* field, const Type& value) const;
const FieldDescriptor* field, Type value) const;
template <typename Type>
inline Type* AddField(Message* message,
const FieldDescriptor* field) const;
@ -388,11 +392,6 @@ inline To dynamic_cast_if_available(From from) {
#endif
}
// Compute the space used by a string, not including sizeof(string) itself.
// This is slightly complicated because small strings store their data within
// the string object but large strings do not.
LIBPROTOBUF_EXPORT int StringSpaceUsedExcludingSelf(const string& str);
// Helper for EnumType_Parse functions: try to parse the string 'name' as an
// enum name of the given type, returning true and filling in value on success,
// or returning false and leaving value unchanged on failure.
@ -415,7 +414,6 @@ bool ParseNamedEnum(const EnumDescriptor* descriptor,
// descriptor.h.
LIBPROTOBUF_EXPORT const string& NameOfEnum(const EnumDescriptor* descriptor, int value);
} // namespace internal
} // namespace protobuf

View File

@ -0,0 +1,44 @@
// 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: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/generated_message_util.h>
namespace google {
namespace protobuf {
namespace internal {
} // namespace internal
} // namespace protobuf
} // namespace google

View File

@ -0,0 +1,65 @@
// 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: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
//
// This file contains miscellaneous helper code used by generated code --
// including lite types -- but which should not be used directly by users.
#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
#include <google/protobuf/stubs/common.h>
namespace google {
namespace protobuf {
namespace internal {
// Annotation for the compiler to emit a deprecation message if a field marked
// with option 'deprecated=true' is used in the code.
//
// For internal use in the pb.cc files, deprecation warnings are suppressed
// there.
#undef DEPRECATED_PROTOBUF_FIELD
#if !defined(INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION)
# define DEPRECATED_PROTOBUF_FIELD GOOGLE_ATTRIBUTE_DEPRECATED
#else
# define DEPRECATED_PROTOBUF_FIELD
#endif
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__

View File

@ -80,18 +80,49 @@ CodedInputStream::CodedInputStream(ZeroCopyInputStream* input)
total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold),
recursion_depth_(0),
recursion_limit_(kDefaultRecursionLimit) {
// Eagerly Refresh() so buffer space is immediately available.
Refresh();
}
CodedInputStream::CodedInputStream(const uint8* buffer, int size)
: input_(NULL),
buffer_(buffer),
buffer_size_(size),
total_bytes_read_(size),
overflow_bytes_(0),
last_tag_(0),
legitimate_message_end_(false),
aliasing_enabled_(false),
current_limit_(size),
buffer_size_after_limit_(0),
total_bytes_limit_(kDefaultTotalBytesLimit),
total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold),
recursion_depth_(0),
recursion_limit_(kDefaultRecursionLimit) {
// Note that setting current_limit_ == size is important to prevent some
// code paths from trying to access input_ and segfaulting.
}
CodedInputStream::~CodedInputStream() {
int backup_bytes = buffer_size_ + buffer_size_after_limit_ + overflow_bytes_;
if (backup_bytes > 0) {
// We still have bytes left over from the last buffer. Back up over
// them.
input_->BackUp(backup_bytes);
if (input_ != NULL) {
BackUpInputToCurrentPosition();
}
}
void CodedInputStream::BackUpInputToCurrentPosition() {
int backup_bytes = buffer_size_ + buffer_size_after_limit_ + overflow_bytes_;
if (backup_bytes > 0) {
input_->BackUp(backup_bytes);
// total_bytes_read_ doesn't include overflow_bytes_.
total_bytes_read_ -= buffer_size_ + buffer_size_after_limit_;
buffer_size_ = 0;
buffer_size_after_limit_ = 0;
overflow_bytes_ = 0;
}
}
inline void CodedInputStream::RecomputeBufferLimits() {
buffer_size_ += buffer_size_after_limit_;
int closest_limit = min(current_limit_, total_bytes_limit_);
@ -193,8 +224,10 @@ bool CodedInputStream::Skip(int count) {
int bytes_until_limit = closest_limit - total_bytes_read_;
if (bytes_until_limit < count) {
// We hit the limit. Skip up to it then fail.
total_bytes_read_ = closest_limit;
input_->Skip(bytes_until_limit);
if (bytes_until_limit > 0) {
total_bytes_read_ = closest_limit;
input_->Skip(bytes_until_limit);
}
return false;
}
@ -216,6 +249,7 @@ bool CodedInputStream::ReadRaw(void* buffer, int size) {
memcpy(buffer, buffer_, buffer_size_);
buffer = reinterpret_cast<uint8*>(buffer) + buffer_size_;
size -= buffer_size_;
Advance(buffer_size_);
if (!Refresh()) return false;
}
@ -247,6 +281,7 @@ bool CodedInputStream::ReadString(string* buffer, int size) {
buffer->append(reinterpret_cast<const char*>(buffer_), buffer_size_);
}
size -= buffer_size_;
Advance(buffer_size_);
if (!Refresh()) return false;
}
@ -441,11 +476,11 @@ bool CodedInputStream::ReadVarint64(uint64* value) {
}
bool CodedInputStream::Refresh() {
if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0) {
// We've hit a limit. Stop.
buffer_ += buffer_size_;
buffer_size_ = 0;
GOOGLE_DCHECK_EQ(buffer_size_, 0);
if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 ||
total_bytes_read_ == current_limit_) {
// We've hit a limit. Stop.
int current_position = total_bytes_read_ - buffer_size_after_limit_;
if (current_position >= total_bytes_limit_ &&
@ -570,10 +605,7 @@ void CodedOutputStream::WriteLittleEndian32(uint32 value) {
bool use_fast = buffer_size_ >= sizeof(value);
uint8* ptr = use_fast ? buffer_ : bytes;
ptr[0] = static_cast<uint8>(value );
ptr[1] = static_cast<uint8>(value >> 8);
ptr[2] = static_cast<uint8>(value >> 16);
ptr[3] = static_cast<uint8>(value >> 24);
WriteLittleEndian32ToArray(value, ptr);
if (use_fast) {
Advance(sizeof(value));
@ -582,32 +614,13 @@ void CodedOutputStream::WriteLittleEndian32(uint32 value) {
}
}
uint8* CodedOutputStream::WriteLittleEndian32ToArray(
uint32 value, uint8* target) {
target[0] = static_cast<uint8>(value );
target[1] = static_cast<uint8>(value >> 8);
target[2] = static_cast<uint8>(value >> 16);
target[3] = static_cast<uint8>(value >> 24);
return target + sizeof(value);
}
void CodedOutputStream::WriteLittleEndian64(uint64 value) {
uint8 bytes[sizeof(value)];
uint32 part0 = static_cast<uint32>(value);
uint32 part1 = static_cast<uint32>(value >> 32);
bool use_fast = buffer_size_ >= sizeof(value);
uint8* ptr = use_fast ? buffer_ : bytes;
ptr[0] = static_cast<uint8>(part0 );
ptr[1] = static_cast<uint8>(part0 >> 8);
ptr[2] = static_cast<uint8>(part0 >> 16);
ptr[3] = static_cast<uint8>(part0 >> 24);
ptr[4] = static_cast<uint8>(part1 );
ptr[5] = static_cast<uint8>(part1 >> 8);
ptr[6] = static_cast<uint8>(part1 >> 16);
ptr[7] = static_cast<uint8>(part1 >> 24);
WriteLittleEndian64ToArray(value, ptr);
if (use_fast) {
Advance(sizeof(value));
@ -616,23 +629,6 @@ void CodedOutputStream::WriteLittleEndian64(uint64 value) {
}
}
uint8* CodedOutputStream::WriteLittleEndian64ToArray(
uint64 value, uint8* target) {
uint32 part0 = static_cast<uint32>(value);
uint32 part1 = static_cast<uint32>(value >> 32);
target[0] = static_cast<uint8>(part0 );
target[1] = static_cast<uint8>(part0 >> 8);
target[2] = static_cast<uint8>(part0 >> 16);
target[3] = static_cast<uint8>(part0 >> 24);
target[4] = static_cast<uint8>(part1 );
target[5] = static_cast<uint8>(part1 >> 8);
target[6] = static_cast<uint8>(part1 >> 16);
target[7] = static_cast<uint8>(part1 >> 24);
return target + sizeof(value);
}
inline uint8* CodedOutputStream::WriteVarint32FallbackToArrayInline(
uint32 value, uint8* target) {
target[0] = static_cast<uint8>(value | 0x80);

View File

@ -110,6 +110,9 @@
#define GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
#include <string>
#ifndef _MSC_VER
#include <sys/param.h>
#endif // !_MSC_VER
#include <google/protobuf/stubs/common.h>
namespace google {
@ -137,6 +140,11 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// Create a CodedInputStream that reads from the given ZeroCopyInputStream.
explicit CodedInputStream(ZeroCopyInputStream* input);
// Create a CodedInputStream that reads from the given flat array. This is
// faster than using an ArrayInputStream. PushLimit(size) is implied by
// this constructor.
explicit CodedInputStream(const uint8* buffer, int size);
// Destroy the CodedInputStream and position the underlying
// ZeroCopyInputStream at the first unread byte. If an error occurred while
// reading (causing a method to return false), then the exact position of
@ -360,6 +368,9 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// Advance the buffer by a given number of bytes.
void Advance(int amount);
// Back up input_ to the current buffer position.
void BackUpInputToCurrentPosition();
// Recomputes the value of buffer_size_after_limit_. Must be called after
// current_limit_ or total_bytes_limit_ changes.
void RecomputeBufferLimits();
@ -664,6 +675,41 @@ inline uint8* CodedOutputStream::WriteVarint32SignExtendedToArray(
}
}
inline uint8* CodedOutputStream::WriteLittleEndian32ToArray(uint32 value,
uint8* target) {
#if !defined(PROTOBUF_TEST_NOT_LITTLE_ENDIAN) && \
defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
memcpy(target, &value, sizeof(value));
#else
target[0] = static_cast<uint8>(value );
target[1] = static_cast<uint8>(value >> 8);
target[2] = static_cast<uint8>(value >> 16);
target[3] = static_cast<uint8>(value >> 24);
#endif
return target + sizeof(value);
}
inline uint8* CodedOutputStream::WriteLittleEndian64ToArray(uint64 value,
uint8* target) {
#if !defined(PROTOBUF_TEST_NOT_LITTLE_ENDIAN) && \
defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
memcpy(target, &value, sizeof(value));
#else
uint32 part0 = static_cast<uint32>(value);
uint32 part1 = static_cast<uint32>(value >> 32);
target[0] = static_cast<uint8>(part0 );
target[1] = static_cast<uint8>(part0 >> 8);
target[2] = static_cast<uint8>(part0 >> 16);
target[3] = static_cast<uint8>(part0 >> 24);
target[4] = static_cast<uint8>(part1 );
target[5] = static_cast<uint8>(part1 >> 8);
target[6] = static_cast<uint8>(part1 >> 16);
target[7] = static_cast<uint8>(part1 >> 24);
#endif
return target + sizeof(value);
}
inline void CodedOutputStream::WriteTag(uint32 value) {
WriteVarint32(value);
}

View File

@ -1,5 +1,5 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2009 Google Inc. All rights reserved.
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
@ -29,8 +29,6 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: brianolson@google.com (Brian Olson)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
//
// This file contains the implementation of classes GzipInputStream and
// GzipOutputStream.
@ -39,6 +37,7 @@
#if HAVE_ZLIB
#include <google/protobuf/io/gzip_stream.h>
#include <google/protobuf/stubs/common.h>
namespace google {
@ -291,6 +290,6 @@ bool GzipOutputStream::Close() {
} // namespace io
} // namespace protobuf
} // namespace google
#endif // HAVE_ZLIB
} // namespace google

View File

@ -1,5 +1,5 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2009 Google Inc. All rights reserved.
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
@ -29,8 +29,6 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: brianolson@google.com (Brian Olson)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
//
// This file contains the definition for classes GzipInputStream and
// GzipOutputStream.
@ -173,6 +171,6 @@ class LIBPROTOBUF_EXPORT GzipOutputStream : public ZeroCopyOutputStream {
} // namespace io
} // namespace protobuf
} // namespace google
} // namespace google
#endif // GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__

View File

@ -571,7 +571,7 @@ bool Tokenizer::ParseInteger(const string& text, uint64 max_value,
const char* ptr = text.c_str();
int base = 10;
if (ptr[0] == '0') {
if (ptr[1] == 'x') {
if (ptr[1] == 'x' || ptr[1] == 'X') {
// This is hex.
base = 16;
ptr += 2;

View File

@ -487,6 +487,7 @@ TEST_F(TokenizerTest, ParseInteger) {
EXPECT_EQ(0xabcdef12u, ParseInteger("0xABCDEF12"));
EXPECT_EQ(kuint64max, ParseInteger("0xFFFFFFFFFFFFFFFF"));
EXPECT_EQ(01234567, ParseInteger("01234567"));
EXPECT_EQ(0X123, ParseInteger("0X123"));
// Test invalid integers that may still be tokenized as integers.
EXPECT_EQ(0, ParseInteger("0x"));

View File

@ -60,7 +60,6 @@ namespace io {
namespace {
// EINTR sucks.
int close_no_eintr(int fd) {
int result;
@ -70,352 +69,8 @@ int close_no_eintr(int fd) {
return result;
}
// Default block size for Copying{In,Out}putStreamAdaptor.
static const int kDefaultBlockSize = 8192;
} // namespace
// ===================================================================
ArrayInputStream::ArrayInputStream(const void* data, int size,
int block_size)
: data_(reinterpret_cast<const uint8*>(data)),
size_(size),
block_size_(block_size > 0 ? block_size : size),
position_(0),
last_returned_size_(0) {
}
ArrayInputStream::~ArrayInputStream() {
}
bool ArrayInputStream::Next(const void** data, int* size) {
if (position_ < size_) {
last_returned_size_ = min(block_size_, size_ - position_);
*data = data_ + position_;
*size = last_returned_size_;
position_ += last_returned_size_;
return true;
} else {
// We're at the end of the array.
last_returned_size_ = 0; // Don't let caller back up.
return false;
}
}
void ArrayInputStream::BackUp(int count) {
GOOGLE_CHECK_GT(last_returned_size_, 0)
<< "BackUp() can only be called after a successful Next().";
GOOGLE_CHECK_LE(count, last_returned_size_);
GOOGLE_CHECK_GE(count, 0);
position_ -= count;
last_returned_size_ = 0; // Don't let caller back up further.
}
bool ArrayInputStream::Skip(int count) {
GOOGLE_CHECK_GE(count, 0);
last_returned_size_ = 0; // Don't let caller back up.
if (count > size_ - position_) {
position_ = size_;
return false;
} else {
position_ += count;
return true;
}
}
int64 ArrayInputStream::ByteCount() const {
return position_;
}
// ===================================================================
ArrayOutputStream::ArrayOutputStream(void* data, int size, int block_size)
: data_(reinterpret_cast<uint8*>(data)),
size_(size),
block_size_(block_size > 0 ? block_size : size),
position_(0),
last_returned_size_(0) {
}
ArrayOutputStream::~ArrayOutputStream() {
}
bool ArrayOutputStream::Next(void** data, int* size) {
if (position_ < size_) {
last_returned_size_ = min(block_size_, size_ - position_);
*data = data_ + position_;
*size = last_returned_size_;
position_ += last_returned_size_;
return true;
} else {
// We're at the end of the array.
last_returned_size_ = 0; // Don't let caller back up.
return false;
}
}
void ArrayOutputStream::BackUp(int count) {
GOOGLE_CHECK_GT(last_returned_size_, 0)
<< "BackUp() can only be called after a successful Next().";
GOOGLE_CHECK_LE(count, last_returned_size_);
GOOGLE_CHECK_GE(count, 0);
position_ -= count;
last_returned_size_ = 0; // Don't let caller back up further.
}
int64 ArrayOutputStream::ByteCount() const {
return position_;
}
// ===================================================================
StringOutputStream::StringOutputStream(string* target)
: target_(target) {
}
StringOutputStream::~StringOutputStream() {
}
bool StringOutputStream::Next(void** data, int* size) {
int old_size = target_->size();
// Grow the string.
if (old_size < target_->capacity()) {
// Resize the string to match its capacity, since we can get away
// without a memory allocation this way.
STLStringResizeUninitialized(target_, target_->capacity());
} else {
// Size has reached capacity, so double the size. Also make sure
// that the new size is at least kMinimumSize.
STLStringResizeUninitialized(
target_,
max(old_size * 2,
kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness.
}
*data = string_as_array(target_) + old_size;
*size = target_->size() - old_size;
return true;
}
void StringOutputStream::BackUp(int count) {
GOOGLE_CHECK_GE(count, 0);
GOOGLE_CHECK_LE(count, target_->size());
target_->resize(target_->size() - count);
}
int64 StringOutputStream::ByteCount() const {
return target_->size();
}
// ===================================================================
// ===================================================================
CopyingInputStream::~CopyingInputStream() {}
int CopyingInputStream::Skip(int count) {
char junk[4096];
int skipped = 0;
while (skipped < count) {
int bytes = Read(junk, min(count - skipped,
implicit_cast<int>(sizeof(junk))));
if (bytes <= 0) {
// EOF or read error.
return skipped;
}
skipped += bytes;
}
return skipped;
}
CopyingInputStreamAdaptor::CopyingInputStreamAdaptor(
CopyingInputStream* copying_stream, int block_size)
: copying_stream_(copying_stream),
owns_copying_stream_(false),
failed_(false),
position_(0),
buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
buffer_used_(0),
backup_bytes_(0) {
}
CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() {
if (owns_copying_stream_) {
delete copying_stream_;
}
}
bool CopyingInputStreamAdaptor::Next(const void** data, int* size) {
if (failed_) {
// Already failed on a previous read.
return false;
}
AllocateBufferIfNeeded();
if (backup_bytes_ > 0) {
// We have data left over from a previous BackUp(), so just return that.
*data = buffer_.get() + buffer_used_ - backup_bytes_;
*size = backup_bytes_;
backup_bytes_ = 0;
return true;
}
// Read new data into the buffer.
buffer_used_ = copying_stream_->Read(buffer_.get(), buffer_size_);
if (buffer_used_ <= 0) {
// EOF or read error. We don't need the buffer anymore.
if (buffer_used_ < 0) {
// Read error (not EOF).
failed_ = true;
}
FreeBuffer();
return false;
}
position_ += buffer_used_;
*size = buffer_used_;
*data = buffer_.get();
return true;
}
void CopyingInputStreamAdaptor::BackUp(int count) {
GOOGLE_CHECK(backup_bytes_ == 0 && buffer_.get() != NULL)
<< " BackUp() can only be called after Next().";
GOOGLE_CHECK_LE(count, buffer_used_)
<< " Can't back up over more bytes than were returned by the last call"
" to Next().";
GOOGLE_CHECK_GE(count, 0)
<< " Parameter to BackUp() can't be negative.";
backup_bytes_ = count;
}
bool CopyingInputStreamAdaptor::Skip(int count) {
GOOGLE_CHECK_GE(count, 0);
if (failed_) {
// Already failed on a previous read.
return false;
}
// First skip any bytes left over from a previous BackUp().
if (backup_bytes_ >= count) {
// We have more data left over than we're trying to skip. Just chop it.
backup_bytes_ -= count;
return true;
}
count -= backup_bytes_;
backup_bytes_ = 0;
int skipped = copying_stream_->Skip(count);
position_ += skipped;
return skipped == count;
}
int64 CopyingInputStreamAdaptor::ByteCount() const {
return position_ - backup_bytes_;
}
void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
if (buffer_.get() == NULL) {
buffer_.reset(new uint8[buffer_size_]);
}
}
void CopyingInputStreamAdaptor::FreeBuffer() {
GOOGLE_CHECK_EQ(backup_bytes_, 0);
buffer_used_ = 0;
buffer_.reset();
}
// ===================================================================
CopyingOutputStream::~CopyingOutputStream() {}
CopyingOutputStreamAdaptor::CopyingOutputStreamAdaptor(
CopyingOutputStream* copying_stream, int block_size)
: copying_stream_(copying_stream),
owns_copying_stream_(false),
failed_(false),
position_(0),
buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
buffer_used_(0) {
}
CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() {
WriteBuffer();
if (owns_copying_stream_) {
delete copying_stream_;
}
}
bool CopyingOutputStreamAdaptor::Flush() {
return WriteBuffer();
}
bool CopyingOutputStreamAdaptor::Next(void** data, int* size) {
if (buffer_used_ == buffer_size_) {
if (!WriteBuffer()) return false;
}
AllocateBufferIfNeeded();
*data = buffer_.get() + buffer_used_;
*size = buffer_size_ - buffer_used_;
buffer_used_ = buffer_size_;
return true;
}
void CopyingOutputStreamAdaptor::BackUp(int count) {
GOOGLE_CHECK_GE(count, 0);
GOOGLE_CHECK_EQ(buffer_used_, buffer_size_)
<< " BackUp() can only be called after Next().";
GOOGLE_CHECK_LE(count, buffer_used_)
<< " Can't back up over more bytes than were returned by the last call"
" to Next().";
buffer_used_ -= count;
}
int64 CopyingOutputStreamAdaptor::ByteCount() const {
return position_ + buffer_used_;
}
bool CopyingOutputStreamAdaptor::WriteBuffer() {
if (failed_) {
// Already failed on a previous write.
return false;
}
if (buffer_used_ == 0) return true;
if (copying_stream_->Write(buffer_.get(), buffer_used_)) {
position_ += buffer_used_;
buffer_used_ = 0;
return true;
} else {
failed_ = true;
FreeBuffer();
return false;
}
}
void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() {
if (buffer_ == NULL) {
buffer_.reset(new uint8[buffer_size_]);
}
}
void CopyingOutputStreamAdaptor::FreeBuffer() {
buffer_used_ = 0;
buffer_.reset();
}
// ===================================================================

Some files were not shown because too many files have changed in this diff Show More