Commit 0400cca3 authored by Adam Cozzette's avatar Adam Cozzette

Integrated internal changes from Google

parent 96b535cc
......@@ -243,3 +243,4 @@ public class ProtoCaliperBenchmark {
}
}
......@@ -115,3 +115,4 @@ class Benchmark:
if __name__ == "__main__":
for i in range(2, len(sys.argv)):
run_one_test(sys.argv[i])
......@@ -79,20 +79,6 @@ copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_field.h" inc
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\service.h" include\google\protobuf\service.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\source_context.pb.h" include\google\protobuf\source_context.pb.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\struct.pb.h" include\google\protobuf\struct.pb.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomic_sequence_num.h" include\google\protobuf\stubs\atomic_sequence_num.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops.h" include\google\protobuf\stubs\atomicops.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_arm64_gcc.h" include\google\protobuf\stubs\atomicops_internals_arm64_gcc.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_arm_gcc.h" include\google\protobuf\stubs\atomicops_internals_arm_gcc.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_arm_qnx.h" include\google\protobuf\stubs\atomicops_internals_arm_qnx.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_generic_c11_atomic.h" include\google\protobuf\stubs\atomicops_internals_generic_c11_atomic.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_generic_gcc.h" include\google\protobuf\stubs\atomicops_internals_generic_gcc.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_mips_gcc.h" include\google\protobuf\stubs\atomicops_internals_mips_gcc.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_power.h" include\google\protobuf\stubs\atomicops_internals_power.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_ppc_gcc.h" include\google\protobuf\stubs\atomicops_internals_ppc_gcc.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_solaris.h" include\google\protobuf\stubs\atomicops_internals_solaris.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_tsan.h" include\google\protobuf\stubs\atomicops_internals_tsan.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_x86_gcc.h" include\google\protobuf\stubs\atomicops_internals_x86_gcc.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_x86_msvc.h" include\google\protobuf\stubs\atomicops_internals_x86_msvc.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\bytestream.h" include\google\protobuf\stubs\bytestream.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\callback.h" include\google\protobuf\stubs\callback.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\casts.h" include\google\protobuf\stubs\casts.h
......@@ -105,8 +91,6 @@ copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\mutex.h" includ
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\once.h" include\google\protobuf\stubs\once.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\platform_macros.h" include\google\protobuf\stubs\platform_macros.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\port.h" include\google\protobuf\stubs\port.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\scoped_ptr.h" include\google\protobuf\stubs\scoped_ptr.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\shared_ptr.h" include\google\protobuf\stubs\shared_ptr.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\singleton.h" include\google\protobuf\stubs\singleton.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\status.h" include\google\protobuf\stubs\status.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\stl_util.h" include\google\protobuf\stubs\stl_util.h
......
......@@ -10,13 +10,10 @@ set(libprotobuf_lite_files
${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
${protobuf_source_dir}/src/google/protobuf/message_lite.cc
${protobuf_source_dir}/src/google/protobuf/repeated_field.cc
${protobuf_source_dir}/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc
${protobuf_source_dir}/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc
${protobuf_source_dir}/src/google/protobuf/stubs/bytestream.cc
${protobuf_source_dir}/src/google/protobuf/stubs/common.cc
${protobuf_source_dir}/src/google/protobuf/stubs/int128.cc
${protobuf_source_dir}/src/google/protobuf/stubs/io_win32.cc
${protobuf_source_dir}/src/google/protobuf/stubs/once.cc
${protobuf_source_dir}/src/google/protobuf/stubs/status.cc
${protobuf_source_dir}/src/google/protobuf/stubs/statusor.cc
${protobuf_source_dir}/src/google/protobuf/stubs/stringpiece.cc
......@@ -38,7 +35,6 @@ set(libprotobuf_lite_includes
${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl_lite.h
${protobuf_source_dir}/src/google/protobuf/message_lite.h
${protobuf_source_dir}/src/google/protobuf/repeated_field.h
${protobuf_source_dir}/src/google/protobuf/stubs/atomicops_internals_x86_msvc.h
${protobuf_source_dir}/src/google/protobuf/stubs/bytestream.h
${protobuf_source_dir}/src/google/protobuf/stubs/common.h
${protobuf_source_dir}/src/google/protobuf/stubs/int128.h
......
......@@ -155,7 +155,8 @@ set(tests_files
${protobuf_source_dir}/src/google/protobuf/preserve_unknown_enum_test.cc
${protobuf_source_dir}/src/google/protobuf/proto3_arena_lite_unittest.cc
${protobuf_source_dir}/src/google/protobuf/proto3_arena_unittest.cc
${protobuf_source_dir}/src/google/protobuf/proto3_lite_unittest.cc
# TODO(b/74491957) Make this unittest work
# ${protobuf_source_dir}/src/google/protobuf/proto3_lite_unittest.cc
${protobuf_source_dir}/src/google/protobuf/reflection_ops_unittest.cc
${protobuf_source_dir}/src/google/protobuf/repeated_field_reflection_unittest.cc
${protobuf_source_dir}/src/google/protobuf/repeated_field_unittest.cc
......@@ -163,7 +164,6 @@ set(tests_files
${protobuf_source_dir}/src/google/protobuf/stubs/common_unittest.cc
${protobuf_source_dir}/src/google/protobuf/stubs/int128_unittest.cc
${protobuf_source_dir}/src/google/protobuf/stubs/io_win32_unittest.cc
${protobuf_source_dir}/src/google/protobuf/stubs/once_unittest.cc
${protobuf_source_dir}/src/google/protobuf/stubs/status_test.cc
${protobuf_source_dir}/src/google/protobuf/stubs/statusor_test.cc
${protobuf_source_dir}/src/google/protobuf/stubs/stringpiece_unittest.cc
......@@ -172,7 +172,6 @@ set(tests_files
${protobuf_source_dir}/src/google/protobuf/stubs/strutil_unittest.cc
${protobuf_source_dir}/src/google/protobuf/stubs/template_util_unittest.cc
${protobuf_source_dir}/src/google/protobuf/stubs/time_test.cc
${protobuf_source_dir}/src/google/protobuf/stubs/type_traits_unittest.cc
${protobuf_source_dir}/src/google/protobuf/text_format_unittest.cc
${protobuf_source_dir}/src/google/protobuf/unknown_field_set_unittest.cc
${protobuf_source_dir}/src/google/protobuf/util/delimited_message_util_test.cc
......
......@@ -1910,6 +1910,10 @@ bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner,
{
TestAllTypesProto3 messageProto3;
TestAllTypesProto2 messageProto2;
//TODO(yilunchong): update this behavior when unknown field's behavior
// changed in open source. Also delete
// Required.Proto3.ProtobufInput.UnknownVarint.ProtobufOutput
// from failure list of python_cpp python java
TestUnknownMessage(messageProto3, true);
TestUnknownMessage(messageProto2, false);
}
......
......@@ -45,3 +45,4 @@ Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValu
Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
Required.Proto3.ProtobufInput.UnknownVarint.ProtobufOutput
\ No newline at end of file
......@@ -19,3 +19,4 @@ Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_0
Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_1
Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_2
Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_3
Required.Proto3.ProtobufInput.UnknownVarint.ProtobufOutput
\ No newline at end of file
......@@ -52,3 +52,4 @@ Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT32
Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64
Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32
Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64
Required.Proto3.ProtobufInput.UnknownVarint.ProtobufOutput
\ No newline at end of file
......@@ -124,6 +124,16 @@ public abstract class AbstractMessage
protected int memoizedSize = -1;
@Override
int getMemoizedSerializedSize() {
return memoizedSize;
}
@Override
void setMemoizedSerializedSize(int size) {
memoizedSize = size;
}
@Override
public int getSerializedSize() {
int size = memoizedSize;
......
......@@ -99,6 +99,16 @@ public abstract class AbstractMessageLite<
codedOutput.flush();
}
// We'd like these to be abstract but some folks are extending this class directly. They shouldn't
// be doing that and they should feel bad.
int getMemoizedSerializedSize() {
throw new UnsupportedOperationException();
}
void setMemoizedSerializedSize(int size) {
throw new UnsupportedOperationException();
}
/**
* Package private helper method for AbstractParser to create
......
......@@ -81,6 +81,18 @@ final class BooleanArrayList extends AbstractProtobufList<Boolean>
this.size = size;
}
@Override
protected void removeRange(int fromIndex, int toIndex) {
ensureIsMutable();
if (toIndex < fromIndex) {
throw new IndexOutOfBoundsException("toIndex < fromIndex");
}
System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
size -= (toIndex - fromIndex);
modCount++;
}
@Override
public boolean equals(Object o) {
if (this == o) {
......@@ -246,7 +258,9 @@ final class BooleanArrayList extends AbstractProtobufList<Boolean>
ensureIsMutable();
ensureIndexInRange(index);
boolean value = array[index];
System.arraycopy(array, index + 1, array, index, size - index);
if (index < size - 1) {
System.arraycopy(array, index + 1, array, index, size - index);
}
size--;
modCount++;
return value;
......
......@@ -66,11 +66,9 @@ public abstract class CodedInputStream {
/**
* Whether to enable our custom UTF-8 decode codepath which does not use {@link StringCoding}.
* Enabled by default, disable by setting
* {@code -Dcom.google.protobuf.enableCustomutf8Decode=false} in JVM args.
* Currently disabled.
*/
private static final boolean ENABLE_CUSTOM_UTF8_DECODE
= !"false".equals(System.getProperty("com.google.protobuf.enableCustomUtf8Decode"));
private static final boolean ENABLE_CUSTOM_UTF8_DECODE = false;
/** Visible for subclasses. See setRecursionLimit() */
int recursionDepth;
......
......@@ -377,6 +377,7 @@ public abstract class CodedOutputStream extends ByteOutput {
public abstract void writeMessage(final int fieldNumber, final MessageLite value)
throws IOException;
/**
* Write a MessageSet extension field to the stream. For historical reasons,
* the wire format differs from normal fields.
......@@ -481,6 +482,7 @@ public abstract class CodedOutputStream extends ByteOutput {
// Abstract to avoid overhead of additional virtual method calls.
public abstract void writeMessageNoTag(final MessageLite value) throws IOException;
//=================================================================
@ExperimentalApi
......@@ -666,6 +668,7 @@ public abstract class CodedOutputStream extends ByteOutput {
return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
* MessageSet extension to the stream. For historical reasons,
......@@ -913,6 +916,7 @@ public abstract class CodedOutputStream extends ByteOutput {
return computeLengthDelimitedFieldSize(value.getSerializedSize());
}
static int computeLengthDelimitedFieldSize(int fieldLength) {
return computeUInt32SizeNoTag(fieldLength) + fieldLength;
}
......@@ -1049,6 +1053,7 @@ public abstract class CodedOutputStream extends ByteOutput {
writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
}
/**
* Write a {@code group} field to the stream.
*
......@@ -1059,6 +1064,7 @@ public abstract class CodedOutputStream extends ByteOutput {
value.writeTo(this);
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code group} field, including tag.
......@@ -1070,6 +1076,7 @@ public abstract class CodedOutputStream extends ByteOutput {
return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code group} field.
......@@ -1079,6 +1086,7 @@ public abstract class CodedOutputStream extends ByteOutput {
return value.getSerializedSize();
}
/**
* Encode and write a varint. {@code value} is treated as
* unsigned, so it won't be sign-extended if negative.
......@@ -1273,6 +1281,7 @@ public abstract class CodedOutputStream extends ByteOutput {
writeMessageNoTag(value);
}
@Override
public final void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
throws IOException {
......@@ -1297,6 +1306,7 @@ public abstract class CodedOutputStream extends ByteOutput {
value.writeTo(this);
}
@Override
public final void write(byte value) throws IOException {
try {
......@@ -1608,6 +1618,7 @@ public abstract class CodedOutputStream extends ByteOutput {
writeMessageNoTag(value);
}
@Override
public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
throws IOException {
......@@ -1632,6 +1643,7 @@ public abstract class CodedOutputStream extends ByteOutput {
value.writeTo(this);
}
@Override
public void write(byte value) throws IOException {
try {
......@@ -1928,6 +1940,7 @@ public abstract class CodedOutputStream extends ByteOutput {
writeMessageNoTag(value);
}
@Override
public void writeMessageSetExtension(int fieldNumber, MessageLite value) throws IOException {
writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
......@@ -1950,6 +1963,7 @@ public abstract class CodedOutputStream extends ByteOutput {
value.writeTo(this);
}
@Override
public void write(byte value) throws IOException {
if (position >= limit) {
......@@ -2456,6 +2470,7 @@ public abstract class CodedOutputStream extends ByteOutput {
writeMessageNoTag(value);
}
@Override
public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
throws IOException {
......@@ -2480,6 +2495,7 @@ public abstract class CodedOutputStream extends ByteOutput {
value.writeTo(this);
}
@Override
public void write(byte value) throws IOException {
if (position == limit) {
......@@ -2759,6 +2775,7 @@ public abstract class CodedOutputStream extends ByteOutput {
writeMessageNoTag(value);
}
@Override
public void writeMessageSetExtension(final int fieldNumber, final MessageLite value)
throws IOException {
......@@ -2783,6 +2800,7 @@ public abstract class CodedOutputStream extends ByteOutput {
value.writeTo(this);
}
@Override
public void write(byte value) throws IOException {
if (position == limit) {
......
......@@ -81,6 +81,18 @@ final class DoubleArrayList extends AbstractProtobufList<Double>
this.size = size;
}
@Override
protected void removeRange(int fromIndex, int toIndex) {
ensureIsMutable();
if (toIndex < fromIndex) {
throw new IndexOutOfBoundsException("toIndex < fromIndex");
}
System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
size -= (toIndex - fromIndex);
modCount++;
}
@Override
public boolean equals(Object o) {
if (this == o) {
......@@ -247,7 +259,9 @@ final class DoubleArrayList extends AbstractProtobufList<Double>
ensureIsMutable();
ensureIndexInRange(index);
double value = array[index];
System.arraycopy(array, index + 1, array, index, size - index);
if (index < size - 1) {
System.arraycopy(array, index + 1, array, index, size - index);
}
size--;
modCount++;
return value;
......
......@@ -339,6 +339,20 @@ public final class DynamicMessage extends AbstractMessage {
this.fields = FieldSet.newFieldSet();
this.unknownFields = UnknownFieldSet.getDefaultInstance();
this.oneofCases = new FieldDescriptor[type.toProto().getOneofDeclCount()];
// A MapEntry has all of its fields present at all times.
if (type.getOptions().getMapEntry()) {
populateMapEntry();
}
}
private void populateMapEntry() {
for (FieldDescriptor field : type.getFields()) {
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
fields.setField(field, getDefaultInstance(field.getMessageType()));
} else {
fields.setField(field, field.getDefaultValue());
}
}
}
// ---------------------------------------------------------------
......@@ -351,6 +365,10 @@ public final class DynamicMessage extends AbstractMessage {
} else {
fields.clear();
}
// A MapEntry has all of its fields present at all times.
if (type.getOptions().getMapEntry()) {
populateMapEntry();
}
unknownFields = UnknownFieldSet.getDefaultInstance();
return this;
}
......
......@@ -81,6 +81,18 @@ final class FloatArrayList extends AbstractProtobufList<Float>
this.size = size;
}
@Override
protected void removeRange(int fromIndex, int toIndex) {
ensureIsMutable();
if (toIndex < fromIndex) {
throw new IndexOutOfBoundsException("toIndex < fromIndex");
}
System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
size -= (toIndex - fromIndex);
modCount++;
}
@Override
public boolean equals(Object o) {
if (this == o) {
......@@ -246,7 +258,9 @@ final class FloatArrayList extends AbstractProtobufList<Float>
ensureIsMutable();
ensureIndexInRange(index);
float value = array[index];
System.arraycopy(array, index + 1, array, index, size - index);
if (index < size - 1) {
System.arraycopy(array, index + 1, array, index, size - index);
}
size--;
modCount++;
return value;
......
......@@ -230,9 +230,13 @@ public abstract class GeneratedMessageLite<
* Called by subclasses to complete parsing. For use by generated code only.
*/
protected void makeImmutable() {
// BEGIN REGULAR
dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
unknownFields.makeImmutable();
// END REGULAR
// BEGIN EXPERIMENTAL
// Protobuf.getInstance().schemaFor(this).makeImmutable(this);
// END EXPERIMENTAL
}
protected final <
......@@ -269,15 +273,15 @@ public abstract class GeneratedMessageLite<
* For use by generated code only.
*/
public static enum MethodToInvoke {
IS_INITIALIZED,
// BEGIN REGULAR
IS_INITIALIZED,
VISIT,
MERGE_FROM_STREAM,
MAKE_IMMUTABLE,
// END REGULAR
// Rely on/modify instance state
GET_MEMOIZED_IS_INITIALIZED,
SET_MEMOIZED_IS_INITIALIZED,
MERGE_FROM_STREAM,
MAKE_IMMUTABLE,
// Rely on static state
NEW_MUTABLE_INSTANCE,
......@@ -339,6 +343,16 @@ public abstract class GeneratedMessageLite<
}
// END REGULAR
@Override
int getMemoizedSerializedSize() {
return memoizedSerializedSize;
}
@Override
void setMemoizedSerializedSize(int size) {
memoizedSerializedSize = size;
}
/**
......@@ -448,6 +462,28 @@ public abstract class GeneratedMessageLite<
return defaultInstance;
}
@Override
public BuilderType mergeFrom(byte[] input, int offset, int length)
throws InvalidProtocolBufferException {
// BEGIN REGULAR
return super.mergeFrom(input, offset, length);
// END REGULAR
// BEGIN EXPERIMENTAL
// copyOnWrite();
// try {
// Protobuf.getInstance().schemaFor(instance).mergeFrom(
// instance, input, offset, offset + length, new ArrayDecoders.Registers());
// } catch (InvalidProtocolBufferException e) {
// throw e;
// } catch (IndexOutOfBoundsException e) {
// throw InvalidProtocolBufferException.truncatedMessage();
// } catch (IOException e) {
// throw new RuntimeException("Reading from byte array should not throw IOException.", e);
// }
// return (BuilderType) this;
// END EXPERIMENTAL
}
@Override
public BuilderType mergeFrom(
com.google.protobuf.CodedInputStream input,
......@@ -455,7 +491,13 @@ public abstract class GeneratedMessageLite<
throws IOException {
copyOnWrite();
try {
// BEGIN REGULAR
instance.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry);
// END REGULAR
// BEGIN EXPERIMENTAL
// Protobuf.getInstance().schemaFor(instance).mergeFrom(
// instance, CodedInputStreamReader.forCodedInput(input), extensionRegistry);
// END EXPERIMENTAL
} catch (RuntimeException e) {
if (e.getCause() instanceof IOException) {
throw (IOException) e.getCause();
......@@ -576,9 +618,7 @@ public abstract class GeneratedMessageLite<
return parseUnknownField(tag, input);
}
if (extensions.isImmutable()) {
extensions = extensions.clone();
}
ensureExtensionsAreMutable();
if (packed) {
int length = input.readRawVarint32();
......@@ -794,10 +834,18 @@ public abstract class GeneratedMessageLite<
if (subBuilder == null) {
subBuilder = extension.getMessageDefaultInstance().newBuilderForType();
}
rawBytes.newCodedInput().readMessage(subBuilder, extensionRegistry);
subBuilder.mergeFrom(rawBytes, extensionRegistry);
MessageLite value = subBuilder.build();
extensions.setField(extension.descriptor, extension.singularToFieldSetType(value));
ensureExtensionsAreMutable().setField(
extension.descriptor, extension.singularToFieldSetType(value));
}
private FieldSet<ExtensionDescriptor> ensureExtensionsAreMutable() {
if (extensions.isImmutable()) {
extensions = extensions.clone();
}
return extensions;
}
private void verifyExtensionContainingType(
......@@ -869,10 +917,12 @@ public abstract class GeneratedMessageLite<
@Override
protected final void makeImmutable() {
super.makeImmutable();
// BEGIN REGULAR
extensions.makeImmutable();
// END REGULAR
}
/**
* Used by subclasses to serialize extensions. Extension ranges may be
* interleaved with field numbers, but we must write them in canonical
......@@ -1468,8 +1518,13 @@ public abstract class GeneratedMessageLite<
if (memoizedIsInitialized == 0) {
return false;
}
// BEGIN EXPERIMENTAL
// boolean isInitialized = Protobuf.getInstance().schemaFor(message).isInitialized(message);
// END EXPERIMENTAL
// BEGIN REGULAR
boolean isInitialized =
message.dynamicMethod(MethodToInvoke.IS_INITIALIZED, Boolean.FALSE) != null;
// END REGULAR
if (shouldMemoize) {
message.dynamicMethod(
MethodToInvoke.SET_MEMOIZED_IS_INITIALIZED, isInitialized ? message : null);
......@@ -1477,10 +1532,6 @@ public abstract class GeneratedMessageLite<
return isInitialized;
}
protected static final <T extends GeneratedMessageLite<T, ?>> void makeImmutable(T message) {
message.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
}
protected static IntList emptyIntList() {
return IntArrayList.emptyList();
}
......@@ -1560,6 +1611,11 @@ public abstract class GeneratedMessageLite<
throws InvalidProtocolBufferException {
return GeneratedMessageLite.parsePartialFrom(defaultInstance, input, extensionRegistry);
}
@Override
public T parsePartialFrom(byte[] input) throws InvalidProtocolBufferException {
return GeneratedMessageLite.parsePartialFrom(defaultInstance, input);
}
}
/**
......@@ -1573,8 +1629,21 @@ public abstract class GeneratedMessageLite<
@SuppressWarnings("unchecked") // Guaranteed by protoc
T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
try {
// BEGIN REGULAR
result.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry);
// END REGULAR
// BEGIN EXPERIMENTAL
// Protobuf.getInstance().schemaFor(result).mergeFrom(
// result, CodedInputStreamReader.forCodedInput(input), extensionRegistry);
// END EXPERIMENTAL
result.makeImmutable();
// BEGIN EXPERIMENTAL
// } catch (IOException e) {
// if (e.getCause() instanceof InvalidProtocolBufferException) {
// throw (InvalidProtocolBufferException) e.getCause();
// }
// throw new InvalidProtocolBufferException(e.getMessage()).setUnfinishedMessage(result);
// END EXPERIMENTAL
} catch (RuntimeException e) {
if (e.getCause() instanceof InvalidProtocolBufferException) {
throw (InvalidProtocolBufferException) e.getCause();
......@@ -1584,6 +1653,34 @@ public abstract class GeneratedMessageLite<
return result;
}
/** A static helper method for parsing a partial from byte array. */
static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(T instance, byte[] input)
throws InvalidProtocolBufferException {
// BEGIN REGULAR
return parsePartialFrom(instance, input, ExtensionRegistryLite.getEmptyRegistry());
// END REGULAR
// BEGIN EXPERIMENTAL
// @SuppressWarnings("unchecked") // Guaranteed by protoc
// T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
// try {
// Protobuf.getInstance().schemaFor(result).mergeFrom(
// result, input, 0, input.length, new ArrayDecoders.Registers());
// result.makeImmutable();
// if (result.memoizedHashCode != 0) {
// throw new RuntimeException();
// }
// } catch (IOException e) {
// if (e.getCause() instanceof InvalidProtocolBufferException) {
// throw (InvalidProtocolBufferException) e.getCause();
// }
// throw new InvalidProtocolBufferException(e.getMessage()).setUnfinishedMessage(result);
// } catch (IndexOutOfBoundsException e) {
// throw InvalidProtocolBufferException.truncatedMessage().setUnfinishedMessage(result);
// }
// return result;
// END EXPERIMENTAL
}
protected static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
T defaultInstance,
CodedInputStream input)
......@@ -1680,8 +1777,7 @@ public abstract class GeneratedMessageLite<
protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
T defaultInstance, byte[] data)
throws InvalidProtocolBufferException {
return checkMessageInitialized(
parsePartialFrom(defaultInstance, data, ExtensionRegistryLite.getEmptyRegistry()));
return checkMessageInitialized(parsePartialFrom(defaultInstance, data));
}
// Validates last tag.
......
......@@ -81,6 +81,18 @@ final class IntArrayList extends AbstractProtobufList<Integer>
this.size = size;
}
@Override
protected void removeRange(int fromIndex, int toIndex) {
ensureIsMutable();
if (toIndex < fromIndex) {
throw new IndexOutOfBoundsException("toIndex < fromIndex");
}
System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
size -= (toIndex - fromIndex);
modCount++;
}
@Override
public boolean equals(Object o) {
if (this == o) {
......@@ -246,7 +258,9 @@ final class IntArrayList extends AbstractProtobufList<Integer>
ensureIsMutable();
ensureIndexInRange(index);
int value = array[index];
System.arraycopy(array, index + 1, array, index, size - index);
if (index < size - 1) {
System.arraycopy(array, index + 1, array, index, size - index);
}
size--;
modCount++;
return value;
......
......@@ -81,6 +81,18 @@ final class LongArrayList extends AbstractProtobufList<Long>
this.size = size;
}
@Override
protected void removeRange(int fromIndex, int toIndex) {
ensureIsMutable();
if (toIndex < fromIndex) {
throw new IndexOutOfBoundsException("toIndex < fromIndex");
}
System.arraycopy(array, toIndex, array, fromIndex, size - toIndex);
size -= (toIndex - fromIndex);
modCount++;
}
@Override
public boolean equals(Object o) {
if (this == o) {
......@@ -246,7 +258,9 @@ final class LongArrayList extends AbstractProtobufList<Long>
ensureIsMutable();
ensureIndexInRange(index);
long value = array[index];
System.arraycopy(array, index + 1, array, index, size - index);
if (index < size - 1) {
System.arraycopy(array, index + 1, array, index, size - index);
}
size--;
modCount++;
return value;
......
......@@ -31,6 +31,7 @@
package com.google.protobuf;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
......@@ -38,20 +39,18 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
/**
* Helps generate {@link String} representations of {@link MessageLite} protos.
*/
// TODO(dweis): Fix map fields.
/** Helps generate {@link String} representations of {@link MessageLite} protos. */
final class MessageLiteToString {
private static final String LIST_SUFFIX = "List";
private static final String BUILDER_LIST_SUFFIX = "OrBuilderList";
private static final String MAP_SUFFIX = "Map";
private static final String BYTES_SUFFIX = "Bytes";
/**
* Returns a {@link String} representation of the {@link MessageLite} object. The first line of
* Returns a {@link String} representation of the {@link MessageLite} object. The first line of
* the {@code String} representation representation includes a comment string to uniquely identify
* the objcet instance. This acts as an indicator that this should not be relied on for
* the object instance. This acts as an indicator that this should not be relied on for
* comparisons.
*
* <p>For use by generated code only.
......@@ -71,8 +70,9 @@ final class MessageLiteToString {
*/
private static void reflectivePrintWithIndent(
MessageLite messageLite, StringBuilder buffer, int indent) {
// Build a map of method name to method. We're looking for methods like getFoo(), hasFoo(), and
// getFooList() which might be useful for building an object's string representation.
// Build a map of method name to method. We're looking for methods like getFoo(), hasFoo(),
// getFooList() and getFooMap() which might be useful for building an object's string
// representation.
Map<String, Method> nameToNoArgMethod = new HashMap<String, Method>();
Map<String, Method> nameToMethod = new HashMap<String, Method>();
Set<String> getters = new TreeSet<String>();
......@@ -89,12 +89,16 @@ final class MessageLiteToString {
for (String getter : getters) {
String suffix = getter.replaceFirst("get", "");
if (suffix.endsWith(LIST_SUFFIX) && !suffix.endsWith(BUILDER_LIST_SUFFIX)) {
String camelCase = suffix.substring(0, 1).toLowerCase()
+ suffix.substring(1, suffix.length() - LIST_SUFFIX.length());
if (suffix.endsWith(LIST_SUFFIX)
&& !suffix.endsWith(BUILDER_LIST_SUFFIX)
// Sometimes people have fields named 'list' that aren't repeated.
&& !suffix.equals(LIST_SUFFIX)) {
String camelCase =
suffix.substring(0, 1).toLowerCase()
+ suffix.substring(1, suffix.length() - LIST_SUFFIX.length());
// Try to reflectively get the value and toString() the field as if it were repeated. This
// only works if the method names have not be proguarded out or renamed.
Method listMethod = nameToNoArgMethod.get("get" + suffix);
// only works if the method names have not been proguarded out or renamed.
Method listMethod = nameToNoArgMethod.get(getter);
if (listMethod != null && listMethod.getReturnType().equals(List.class)) {
printField(
buffer,
......@@ -104,6 +108,30 @@ final class MessageLiteToString {
continue;
}
}
if (suffix.endsWith(MAP_SUFFIX)
// Sometimes people have fields named 'map' that aren't maps.
&& !suffix.equals(MAP_SUFFIX)) {
String camelCase =
suffix.substring(0, 1).toLowerCase()
+ suffix.substring(1, suffix.length() - MAP_SUFFIX.length());
// Try to reflectively get the value and toString() the field as if it were a map. This only
// works if the method names have not been proguarded out or renamed.
Method mapMethod = nameToNoArgMethod.get(getter);
if (mapMethod != null
&& mapMethod.getReturnType().equals(Map.class)
// Skip the deprecated getter method with no prefix "Map" when the field name ends with
// "map".
&& !mapMethod.isAnnotationPresent(Deprecated.class)
// Skip the internal mutable getter method.
&& Modifier.isPublic(mapMethod.getModifiers())) {
printField(
buffer,
indent,
camelCaseToSnakeCase(camelCase),
GeneratedMessageLite.invokeOrDie(mapMethod, messageLite));
continue;
}
}
Method setter = nameToMethod.get("set" + suffix);
if (setter == null) {
......@@ -119,22 +147,19 @@ final class MessageLiteToString {
String camelCase = suffix.substring(0, 1).toLowerCase() + suffix.substring(1);
// Try to reflectively get the value and toString() the field as if it were optional. This
// only works if the method names have not be proguarded out or renamed.
// only works if the method names have not been proguarded out or renamed.
Method getMethod = nameToNoArgMethod.get("get" + suffix);
Method hasMethod = nameToNoArgMethod.get("has" + suffix);
// TODO(dweis): Fix proto3 semantics.
if (getMethod != null) {
Object value = GeneratedMessageLite.invokeOrDie(getMethod, messageLite);
final boolean hasValue = hasMethod == null
? !isDefaultValue(value)
: (Boolean) GeneratedMessageLite.invokeOrDie(hasMethod, messageLite);
// TODO(dweis): This doesn't stop printing oneof case twice: value and enum style.
final boolean hasValue =
hasMethod == null
? !isDefaultValue(value)
: (Boolean) GeneratedMessageLite.invokeOrDie(hasMethod, messageLite);
// TODO(dweis): This doesn't stop printing oneof case twice: value and enum style.
if (hasValue) {
printField(
buffer,
indent,
camelCaseToSnakeCase(camelCase),
value);
printField(buffer, indent, camelCaseToSnakeCase(camelCase), value);
}
continue;
}
......@@ -153,7 +178,7 @@ final class MessageLiteToString {
((GeneratedMessageLite<?, ?>) messageLite).unknownFields.printWithIndent(buffer, indent);
}
}
private static boolean isDefaultValue(Object o) {
if (o instanceof Boolean) {
return !((Boolean) o);
......@@ -179,7 +204,7 @@ final class MessageLiteToString {
if (o instanceof java.lang.Enum<?>) { // Catches oneof enums.
return ((java.lang.Enum<?>) o).ordinal() == 0;
}
return false;
}
......@@ -201,6 +226,13 @@ final class MessageLiteToString {
}
return;
}
if (object instanceof Map<?, ?>) {
Map<?, ?> map = (Map<?, ?>) object;
for (Map.Entry<?, ?> entry : map.entrySet()) {
printField(buffer, indent, name, entry);
}
return;
}
buffer.append('\n');
for (int i = 0; i < indent; i++) {
......@@ -220,11 +252,21 @@ final class MessageLiteToString {
buffer.append(' ');
}
buffer.append("}");
} else if (object instanceof Map.Entry<?, ?>) {
buffer.append(" {");
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object;
printField(buffer, indent + 2, "key", entry.getKey());
printField(buffer, indent + 2, "value", entry.getValue());
buffer.append("\n");
for (int i = 0; i < indent; i++) {
buffer.append(' ');
}
buffer.append("}");
} else {
buffer.append(": ").append(object.toString());
}
}
private static final String camelCaseToSnakeCase(String camelCase) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < camelCase.length(); i++) {
......
......@@ -987,7 +987,7 @@ public final class TextFormat {
nextToken();
return false;
} else {
throw parseException("Expected \"true\" or \"false\".");
throw parseException("Expected \"true\" or \"false\". Found \"" + currentToken + "\".");
}
}
......@@ -1311,13 +1311,17 @@ public final class TextFormat {
}
private final boolean allowUnknownFields;
private final boolean allowUnknownEnumValues;
private final SingularOverwritePolicy singularOverwritePolicy;
private TextFormatParseInfoTree.Builder parseInfoTreeBuilder;
private Parser(
boolean allowUnknownFields, SingularOverwritePolicy singularOverwritePolicy,
boolean allowUnknownFields,
boolean allowUnknownEnumValues,
SingularOverwritePolicy singularOverwritePolicy,
TextFormatParseInfoTree.Builder parseInfoTreeBuilder) {
this.allowUnknownFields = allowUnknownFields;
this.allowUnknownEnumValues = allowUnknownEnumValues;
this.singularOverwritePolicy = singularOverwritePolicy;
this.parseInfoTreeBuilder = parseInfoTreeBuilder;
}
......@@ -1334,6 +1338,7 @@ public final class TextFormat {
*/
public static class Builder {
private boolean allowUnknownFields = false;
private boolean allowUnknownEnumValues = false;
private SingularOverwritePolicy singularOverwritePolicy =
SingularOverwritePolicy.ALLOW_SINGULAR_OVERWRITES;
private TextFormatParseInfoTree.Builder parseInfoTreeBuilder = null;
......@@ -1355,7 +1360,10 @@ public final class TextFormat {
public Parser build() {
return new Parser(
allowUnknownFields, singularOverwritePolicy, parseInfoTreeBuilder);
allowUnknownFields,
allowUnknownEnumValues,
singularOverwritePolicy,
parseInfoTreeBuilder);
}
}
......@@ -1419,7 +1427,7 @@ public final class TextFormat {
return text;
}
// Check both unknown fields and unknown extensions and log warming messages
// Check both unknown fields and unknown extensions and log warning messages
// or throw exceptions according to the flag.
private void checkUnknownFields(final List<String> unknownFields)
throws ParseException {
......@@ -1737,17 +1745,40 @@ public final class TextFormat {
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 + '.');
String unknownValueMsg =
"Enum type \""
+ enumType.getFullName()
+ "\" has no value with number "
+ number
+ '.';
if (allowUnknownEnumValues) {
logger.warning(unknownValueMsg);
return;
} else {
throw tokenizer.parseExceptionPreviousToken(
"Enum type \""
+ enumType.getFullName()
+ "\" has no value with number "
+ number
+ '.');
}
}
} else {
final String id = tokenizer.consumeIdentifier();
value = enumType.findValueByName(id);
if (value == null) {
throw tokenizer.parseExceptionPreviousToken(
"Enum type \"" + enumType.getFullName()
+ "\" has no value named \"" + id + "\".");
String unknownValueMsg =
"Enum type \""
+ enumType.getFullName()
+ "\" has no value named \""
+ id
+ "\".";
if (allowUnknownEnumValues) {
logger.warning(unknownValueMsg);
return;
} else {
throw tokenizer.parseExceptionPreviousToken(unknownValueMsg);
}
}
}
......
......@@ -295,14 +295,30 @@ public final class UnknownFieldSetLite {
return true;
}
private static int hashCode(int[] tags, int count) {
int hashCode = 17;
for (int i = 0; i < count; ++i) {
hashCode = 31 * hashCode + tags[i];
}
return hashCode;
}
private static int hashCode(Object[] objects, int count) {
int hashCode = 17;
for (int i = 0; i < count; ++i) {
hashCode = 31 * hashCode + objects[i].hashCode();
}
return hashCode;
}
@Override
public int hashCode() {
int hashCode = 17;
hashCode = 31 * hashCode + count;
hashCode = 31 * hashCode + Arrays.hashCode(tags);
hashCode = 31 * hashCode + Arrays.deepHashCode(objects);
hashCode = 31 * hashCode + hashCode(tags, count);
hashCode = 31 * hashCode + hashCode(objects, count);
return hashCode;
}
......
......@@ -33,6 +33,7 @@ package com.google.protobuf;
import java.lang.reflect.Field;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.util.logging.Level;
......@@ -83,6 +84,7 @@ final class UnsafeUtil {
return HAS_UNSAFE_BYTEBUFFER_OPERATIONS;
}
static long objectFieldOffset(Field field) {
return MEMORY_ACCESSOR.objectFieldOffset(field);
}
......@@ -287,7 +289,7 @@ final class UnsafeUtil {
/**
* Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this platform.
*/
private static sun.misc.Unsafe getUnsafe() {
static sun.misc.Unsafe getUnsafe() {
sun.misc.Unsafe unsafe = null;
try {
unsafe =
......@@ -367,6 +369,10 @@ final class UnsafeUtil {
clazz.getMethod("objectFieldOffset", Field.class);
clazz.getMethod("getLong", Object.class, long.class);
if (bufferAddressField() == null) {
return false;
}
clazz.getMethod("getByte", long.class);
clazz.getMethod("putByte", long.class, byte.class);
clazz.getMethod("getInt", long.class);
......@@ -387,12 +393,14 @@ final class UnsafeUtil {
/** Finds the address field within a direct {@link Buffer}. */
private static Field bufferAddressField() {
return field(Buffer.class, "address", long.class);
Field field = field(Buffer.class, "address");
return field != null && field.getType() == long.class ? field : null;
}
/** Finds the value field within a {@link String}. */
private static Field stringValueField() {
return field(String.class, "value", char[].class);
Field field = field(String.class, "value");
return field != null && field.getType() == char[].class ? field : null;
}
/**
......@@ -407,14 +415,11 @@ final class UnsafeUtil {
* Gets the field with the given name within the class, or {@code null} if not found. If found,
* the field is made accessible.
*/
private static Field field(Class<?> clazz, String fieldName, Class<?> expectedType) {
private static Field field(Class<?> clazz, String fieldName) {
Field field;
try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
if (!field.getType().equals(expectedType)) {
return null;
}
} catch (Throwable t) {
// Failed to access the fields.
field = null;
......
......@@ -32,6 +32,7 @@ package com.google.protobuf;
import static java.util.Arrays.asList;
import com.google.protobuf.Internal.BooleanList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
......@@ -297,6 +298,20 @@ public class BooleanArrayListTest extends TestCase {
}
}
public void testRemoveEndOfCapacity() {
BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addBoolean(true);
toRemove.remove(0);
assertEquals(0, toRemove.size());
}
public void testSublistRemoveEndOfCapacity() {
BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addBoolean(true);
toRemove.subList(0, 1).clear();
assertEquals(0, toRemove.size());
}
private void assertImmutable(BooleanArrayList list) {
try {
......
......@@ -34,7 +34,7 @@ import proto2_test_check_utf8.TestCheckUtf8.BytesWrapper;
import proto2_test_check_utf8.TestCheckUtf8.StringWrapper;
import proto2_test_check_utf8_size.TestCheckUtf8Size.BytesWrapperSize;
import proto2_test_check_utf8_size.TestCheckUtf8Size.StringWrapperSize;
import java.io.ByteArrayInputStream;
import junit.framework.TestCase;
/**
......@@ -90,14 +90,9 @@ public class CheckUtf8Test extends TestCase {
}
public void testParseRequiredStringWithBadUtf8() throws Exception {
ByteString serialized =
BytesWrapper.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
try {
StringWrapper.parser().parseFrom(serialized);
fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
} catch (InvalidProtocolBufferException exception) {
assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
}
byte[] serialized =
BytesWrapper.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteArray();
assertParseBadUtf8(StringWrapper.getDefaultInstance(), serialized);
}
public void testBuildRequiredStringWithBadUtf8Size() throws Exception {
......@@ -128,14 +123,36 @@ public class CheckUtf8Test extends TestCase {
}
public void testParseRequiredStringWithBadUtf8Size() throws Exception {
ByteString serialized =
BytesWrapperSize.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
byte[] serialized =
BytesWrapperSize.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteArray();
assertParseBadUtf8(StringWrapperSize.getDefaultInstance(), serialized);
}
private void assertParseBadUtf8(MessageLite defaultInstance, byte[] data) throws Exception {
// Check combinations of (parser vs. builder) x (byte[] vs. InputStream)
try {
defaultInstance.getParserForType().parseFrom(data);
fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
} catch (InvalidProtocolBufferException exception) {
assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
}
try {
defaultInstance.newBuilderForType().mergeFrom(data);
fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
} catch (InvalidProtocolBufferException exception) {
assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
}
try {
StringWrapperSize.parser().parseFrom(serialized);
defaultInstance.getParserForType().parseFrom(new ByteArrayInputStream(data));
fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
} catch (InvalidProtocolBufferException exception) {
assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
}
try {
defaultInstance.newBuilderForType().mergeFrom(new ByteArrayInputStream(data));
fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
} catch (InvalidProtocolBufferException exception) {
assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
}
}
}
......@@ -32,6 +32,7 @@ package com.google.protobuf;
import static java.util.Arrays.asList;
import com.google.protobuf.Internal.DoubleList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
......@@ -297,6 +298,20 @@ public class DoubleArrayListTest extends TestCase {
}
}
public void testRemoveEndOfCapacity() {
DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addDouble(3);
toRemove.remove(0);
assertEquals(0, toRemove.size());
}
public void testSublistRemoveEndOfCapacity() {
DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addDouble(3);
toRemove.subList(0, 1).clear();
assertEquals(0, toRemove.size());
}
private void assertImmutable(DoubleArrayList list) {
if (list.contains(1D)) {
throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
......
......@@ -32,6 +32,7 @@ package com.google.protobuf;
import static java.util.Arrays.asList;
import com.google.protobuf.Internal.FloatList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
......@@ -297,6 +298,20 @@ public class FloatArrayListTest extends TestCase {
}
}
public void testRemoveEndOfCapacity() {
FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addFloat(3);
toRemove.remove(0);
assertEquals(0, toRemove.size());
}
public void testSublistRemoveEndOfCapacity() {
FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addFloat(3);
toRemove.subList(0, 1).clear();
assertEquals(0, toRemove.size());
}
private void assertImmutable(FloatArrayList list) {
if (list.contains(1F)) {
throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
......
......@@ -32,6 +32,7 @@ package com.google.protobuf;
import static java.util.Arrays.asList;
import com.google.protobuf.Internal.IntList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
......@@ -297,6 +298,20 @@ public class IntArrayListTest extends TestCase {
}
}
public void testRemoveEndOfCapacity() {
IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addInt(3);
toRemove.remove(0);
assertEquals(0, toRemove.size());
}
public void testSublistRemoveEndOfCapacity() {
IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addInt(3);
toRemove.subList(0, 1).clear();
assertEquals(0, toRemove.size());
}
private void assertImmutable(IntArrayList list) {
if (list.contains(1)) {
throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -32,6 +32,7 @@ package com.google.protobuf;
import static java.util.Arrays.asList;
import com.google.protobuf.Internal.LongList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
......@@ -297,6 +298,20 @@ public class LongArrayListTest extends TestCase {
}
}
public void testRemoveEndOfCapacity() {
LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addLong(3);
toRemove.remove(0);
assertEquals(0, toRemove.size());
}
public void testSublistRemoveEndOfCapacity() {
LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1);
toRemove.addLong(3);
toRemove.subList(0, 1).clear();
assertEquals(0, toRemove.size());
}
private void assertImmutable(LongArrayList list) {
if (list.contains(1L)) {
throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
......
......@@ -788,6 +788,24 @@ public class MapForProto2Test extends TestCase {
assertEquals(message.hashCode(), dynamicMessage.hashCode());
}
// Check that DynamicMessage handles map field serialization the same way as generated code
// regarding unset key and value field in a map entry.
public void testDynamicMessageUnsetKeyAndValue() throws Exception {
FieldDescriptor field = f("int32_to_int32_field");
Message dynamicDefaultInstance =
DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
Message.Builder builder = dynamicDefaultInstance.newBuilderForType();
// Add an entry without key and value.
builder.addRepeatedField(field, builder.newBuilderForField(field).build());
Message message = builder.build();
ByteString bytes = message.toByteString();
// Parse it back to the same generated type.
Message generatedMessage = TestMap.parseFrom(bytes);
// Assert the serialized bytes are equivalent.
assertEquals(generatedMessage.toByteString(), bytes);
}
public void testReflectionEqualsAndHashCode() throws Exception {
// Test that generated equals() and hashCode() will disregard the order
// of map entries when comparing/hashing map fields.
......
......@@ -893,6 +893,24 @@ public class MapTest extends TestCase {
assertEquals(message.hashCode(), dynamicMessage.hashCode());
}
// Check that DynamicMessage handles map field serialization the same way as generated code
// regarding unset key and value field in a map entry.
public void testDynamicMessageUnsetKeyAndValue() throws Exception {
FieldDescriptor field = f("int32_to_int32_field");
Message dynamicDefaultInstance =
DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
Message.Builder builder = dynamicDefaultInstance.newBuilderForType();
// Add an entry without key and value.
builder.addRepeatedField(field, builder.newBuilderForField(field).build());
Message message = builder.build();
ByteString bytes = message.toByteString();
// Parse it back to the same generated type.
Message generatedMessage = TestMap.parseFrom(bytes);
// Assert the serialized bytes are equivalent.
assertEquals(generatedMessage.toByteString(), bytes);
}
public void testReflectionEqualsAndHashCode() throws Exception {
// Test that generated equals() and hashCode() will disregard the order
// of map entries when comparing/hashing map fields.
......
......@@ -61,12 +61,11 @@ import junit.framework.TestCase;
public class TextFormatTest extends TestCase {
// A basic string with different escapable characters for testing.
private final static String kEscapeTestString =
"\"A string with ' characters \n and \r newlines and \t tabs and \001 "
+ "slashes \\";
private static final String ESCAPE_TEST_STRING =
"\"A string with ' characters \n and \r newlines and \t tabs and \001 " + "slashes \\";
// A representation of the above string with all the characters escaped.
private final static String kEscapeTestStringEscaped =
private static final String ESCAPE_TEST_STRING_ESCAPED =
"\\\"A string with \\' characters \\n and \\r newlines "
+ "and \\t tabs and \\001 slashes \\\\";
......@@ -576,10 +575,10 @@ public class TextFormatTest extends TestCase {
"integer: 82301481290849012385230157",
"optional_int32: 82301481290849012385230157");
assertParseError(
"1:16: Expected \"true\" or \"false\".",
"1:16: Expected \"true\" or \"false\". Found \"maybe\".",
"optional_bool: maybe");
assertParseError(
"1:16: Expected \"true\" or \"false\".",
"1:16: Expected \"true\" or \"false\". Found \"2\".",
"optional_bool: 2");
assertParseError(
"1:18: Expected string.",
......@@ -643,10 +642,8 @@ public class TextFormatTest extends TestCase {
TextFormat.unescapeBytes("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
assertEquals("\0\001\007\b\f\n\r\t\013\\\'\"",
TextFormat.unescapeText("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
assertEquals(kEscapeTestStringEscaped,
TextFormat.escapeText(kEscapeTestString));
assertEquals(kEscapeTestString,
TextFormat.unescapeText(kEscapeTestStringEscaped));
assertEquals(ESCAPE_TEST_STRING_ESCAPED, TextFormat.escapeText(ESCAPE_TEST_STRING));
assertEquals(ESCAPE_TEST_STRING, TextFormat.unescapeText(ESCAPE_TEST_STRING_ESCAPED));
// Invariant
assertEquals("hello",
......
......@@ -30,6 +30,8 @@
package com.google.protobuf;
import static junit.framework.TestCase.assertEquals;
import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
import com.google.protobuf.UnittestLite.TestAllTypesLite;
import protobuf_unittest.UnittestProto;
......@@ -133,6 +135,25 @@ public class UnknownFieldSetLiteTest extends TestCase {
assertEquals(foo.toByteString().size(), instance.getSerializedSize());
}
public void testHashCodeAfterDeserialization() throws IOException {
Foo foo = Foo.newBuilder()
.setValue(2)
.build();
Foo fooDeserialized = Foo.parseFrom(foo.toByteArray());
assertEquals(fooDeserialized, foo);
assertEquals(foo.hashCode(), fooDeserialized.hashCode());
}
public void testNewInstanceHashCode() {
UnknownFieldSetLite emptyFieldSet = UnknownFieldSetLite.getDefaultInstance();
UnknownFieldSetLite paddedFieldSet = UnknownFieldSetLite.newInstance();
assertEquals(emptyFieldSet, paddedFieldSet);
assertEquals(emptyFieldSet.hashCode(), paddedFieldSet.hashCode());
}
public void testMergeVarintField() throws IOException {
UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance();
unknownFields.mergeVarintField(10, 2);
......
......@@ -36,6 +36,7 @@ import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
import protobuf_unittest.UnittestProto;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestExtensionInsideTable;
import protobuf_unittest.UnittestProto.TestFieldOrderings;
import protobuf_unittest.UnittestProto.TestOneof2;
import protobuf_unittest.UnittestProto.TestOneofBackwardsCompatible;
......@@ -235,6 +236,26 @@ public class WireFormatTest extends TestCase {
getTestFieldOrderingsRegistry());
assertEquals(source, dest);
}
private static ExtensionRegistry getTestExtensionInsideTableRegistry() {
ExtensionRegistry result = ExtensionRegistry.newInstance();
result.add(UnittestProto.testExtensionInsideTableExtension);
return result;
}
public void testExtensionInsideTable() throws Exception {
// Make sure the extension within the range of table is parsed correctly in experimental
// runtime.
TestExtensionInsideTable source =
TestExtensionInsideTable.newBuilder()
.setField1(1)
.setExtension(UnittestProto.testExtensionInsideTableExtension, 23)
.build();
TestExtensionInsideTable dest =
TestExtensionInsideTable.parseFrom(source.toByteString(),
getTestExtensionInsideTableRegistry());
assertEquals(source, dest);
}
public void testParseMultipleExtensionRangesDynamic() throws Exception {
// Same as above except with DynamicMessage.
......
......@@ -60,14 +60,25 @@ goog.forwardDeclare('jsproto.BinaryExtension');
/**
* Base interface class for all const messages. Does __not__ define any
* methods, as doing so on a widely-used interface defeats dead-code
* elimination.
* Base interface class for all const messages.
* @interface
*/
jspb.ConstBinaryMessage = function() {};
/**
* Generate a debug string for this proto that is in proto2 text format.
* @return {string} The debug string.
*/
jspb.ConstBinaryMessage.prototype.toDebugString;
/**
* Helper to generate a debug string for this proto at some indent level. The
* first line is not indented.
* @param {number} indentLevel The number of spaces by which to indent lines.
* @return {string} The debug string.
* @protected
*/
jspb.ConstBinaryMessage.prototype.toDebugStringInternal;
/**
* Base interface class for all messages. Does __not__ define any methods, as
......@@ -97,6 +108,7 @@ jspb.ScalarFieldType;
* A repeated field in jspb is an array of scalars, blobs, or messages.
* @typedef {!Array<jspb.ScalarFieldType>|
!Array<!Uint8Array>|
!Array<!jspb.ConstBinaryMessage>|
!Array<!jspb.BinaryMessage>}
*/
jspb.RepeatedFieldType;
......@@ -108,6 +120,7 @@ jspb.RepeatedFieldType;
* @typedef {jspb.ScalarFieldType|
jspb.RepeatedFieldType|
!Uint8Array|
!jspb.ConstBinaryMessage|
!jspb.BinaryMessage|
!jsproto.BinaryExtension}
*/
......
......@@ -986,7 +986,7 @@ jspb.BinaryDecoder.prototype.readString = function(length) {
codeUnits.push(high, low);
}
// Avoid exceeding the maximum stack size when calling {@code apply}.
// Avoid exceeding the maximum stack size when calling `apply`.
if (codeUnits.length >= 8192) {
result += String.fromCharCode.apply(null, codeUnits);
codeUnits.length = 0;
......
......@@ -236,10 +236,12 @@ jspb.BinaryWriter.prototype.getResultBuffer = function() {
/**
* Converts the encoded data into a base64-encoded string.
* @param {boolean=} opt_webSafe True indicates we should use a websafe
* alphabet, which does not require escaping for use in URLs.
* @return {string}
*/
jspb.BinaryWriter.prototype.getResultBase64String = function() {
return goog.crypt.base64.encodeByteArray(this.getResultBuffer());
jspb.BinaryWriter.prototype.getResultBase64String = function(opt_webSafe) {
return goog.crypt.base64.encodeByteArray(this.getResultBuffer(), opt_webSafe);
};
......
......@@ -118,4 +118,16 @@ describe('binaryWriterTest', function() {
var buffer = writer.getResultBuffer();
assertEquals(expected, goog.crypt.byteArrayToHex(buffer));
});
/**
* Tests websafe encodings for base64 strings.
*/
it('testWebSafeOption', function() {
var writer = new jspb.BinaryWriter();
writer.writeBytes(1, new Uint8Array([127]));
assertEquals('CgF/', writer.getResultBase64String());
assertEquals('CgF/', writer.getResultBase64String(false));
assertEquals('CgF_', writer.getResultBase64String(true));
});
});
......@@ -42,7 +42,7 @@ goog.require('jspb.Message');
/**
* Turns a proto into a human readable object that can i.e. be written to the
* console: {@code console.log(jspb.debug.dump(myProto))}.
* console: `console.log(jspb.debug.dump(myProto))`.
* This function makes a best effort and may not work in all cases. It will not
* work in obfuscated and or optimized code.
* Use this in environments where {@see jspb.Message.prototype.toObject} is
......
......@@ -48,9 +48,9 @@ goog.forwardDeclare('jspb.BinaryWriter');
*
* @template K, V
*
* @param {!Array<!Array<!Object>>} arr
* @param {!Array<!Array<?>>} arr
*
* @param {?function(new:V)|function(new:V,?)=} opt_valueCtor
* @param {?function(new:V, ?=)=} opt_valueCtor
* The constructor for type V, if type V is a message type.
*
* @constructor
......@@ -118,7 +118,7 @@ jspb.Map.prototype.toArray = function() {
strKeys.sort();
for (var i = 0; i < strKeys.length; i++) {
var entry = this.map_[strKeys[i]];
var valueWrapper = /** @type {!Object} */ (entry.valueWrapper);
var valueWrapper = /** @type {?jspb.Message} */ (entry.valueWrapper);
if (valueWrapper) {
valueWrapper.toArray();
}
......@@ -165,7 +165,7 @@ jspb.Map.prototype.toObject = function(includeInstance, valueToObject) {
*
* @template K, V
* @param {!Array<!Array<!Object>>} entries
* @param {!function(new:V)|function(new:V,?)} valueCtor
* @param {!function(new:V,?=)} valueCtor
* The constructor for type V.
* @param {!function(!Object):V} valueFromObject
* The fromObject function for type V.
......@@ -432,7 +432,8 @@ jspb.Map.prototype.serializeBinary = function(
valueWriterFn.call(writer, 2, this.wrapEntry_(entry),
opt_valueWriterCallback);
} else {
valueWriterFn.call(writer, 2, entry.value);
/** @type {function(this:jspb.BinaryWriter,number,?)} */ (valueWriterFn)
.call(writer, 2, entry.value);
}
writer.endSubMessage();
}
......@@ -475,10 +476,13 @@ jspb.Map.deserializeBinary = function(map, reader, keyReaderFn, valueReaderFn,
} else if (field == 2) {
// Value.
if (map.valueCtor_) {
goog.asserts.assert(opt_valueReaderCallback);
value = new map.valueCtor_();
valueReaderFn.call(reader, value, opt_valueReaderCallback);
} else {
value = valueReaderFn.call(reader);
value =
(/** @type {function(this:jspb.BinaryReader):?} */ (valueReaderFn))
.call(reader);
}
}
}
......
......@@ -215,17 +215,6 @@ goog.define('jspb.Message.ASSUME_LOCAL_ARRAYS', false);
goog.define('jspb.Message.SERIALIZE_EMPTY_TRAILING_FIELDS', true);
/**
* @define {boolean} Turning on this flag does NOT change the behavior of JSPB
* and only affects private internal state. It may, however, break some
* tests that use naive deeply-equals algorithms, because using a proto
* mutates its internal state.
* Projects are advised to turn this flag always on.
*/
goog.define('jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS', true);
// TODO(b/19419436): Delete this flag.
/**
* Does this JavaScript environment support Uint8Aray typed arrays?
* @type {boolean}
......@@ -369,7 +358,7 @@ jspb.Message.getFieldNumber_ = function(msg, index) {
*/
jspb.Message.initialize = function(
msg, data, messageId, suggestedPivot, repeatedFields, opt_oneofFields) {
msg.wrappers_ = jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS ? null : {};
msg.wrappers_ = null;
if (!data) {
data = messageId ? [messageId] : [];
}
......@@ -394,17 +383,12 @@ jspb.Message.initialize = function(
var fieldNumber = repeatedFields[i];
if (fieldNumber < msg.pivot_) {
var index = jspb.Message.getIndex_(msg, fieldNumber);
msg.array[index] = msg.array[index] ||
(jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS ?
jspb.Message.EMPTY_LIST_SENTINEL_ :
[]);
msg.array[index] =
msg.array[index] || jspb.Message.EMPTY_LIST_SENTINEL_;
} else {
jspb.Message.maybeInitEmptyExtensionObject_(msg);
msg.extensionObject_[fieldNumber] =
msg.extensionObject_[fieldNumber] ||
(jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS ?
jspb.Message.EMPTY_LIST_SENTINEL_ :
[]);
msg.extensionObject_[fieldNumber] = msg.extensionObject_[fieldNumber] ||
jspb.Message.EMPTY_LIST_SENTINEL_;
}
}
}
......@@ -517,8 +501,7 @@ jspb.Message.toObjectList = function(field, toObjectFn, opt_includeInstance) {
// And not using it here to avoid a function call.
var result = [];
for (var i = 0; i < field.length; i++) {
result[i] = toObjectFn.call(field[i], opt_includeInstance,
/** @type {!jspb.Message} */ (field[i]));
result[i] = toObjectFn.call(field[i], opt_includeInstance, field[i]);
}
return result;
};
......@@ -551,10 +534,11 @@ jspb.Message.toObjectExtension = function(proto, obj, extensions,
} else {
if (fieldInfo.isRepeated) {
obj[name] = jspb.Message.toObjectList(
/** @type {!Array<jspb.Message>} */ (value),
/** @type {!Array<!jspb.Message>} */ (value),
fieldInfo.toObjectFn, opt_includeInstance);
} else {
obj[name] = fieldInfo.toObjectFn(opt_includeInstance, value);
obj[name] = fieldInfo.toObjectFn(
opt_includeInstance, /** @type {!jspb.Message} */ (value));
}
}
}
......@@ -1419,7 +1403,7 @@ jspb.Message.prototype.setExtension = function(fieldInfo, value) {
if (fieldInfo.isMessageType()) {
self.wrappers_[fieldNumber] = value;
self.extensionObject_[fieldNumber] = goog.array.map(
/** @type {Array<jspb.Message>} */ (value), function(msg) {
/** @type {!Array<!jspb.Message>} */ (value), function(msg) {
return msg.toArray();
});
} else {
......@@ -1428,7 +1412,8 @@ jspb.Message.prototype.setExtension = function(fieldInfo, value) {
} else {
if (fieldInfo.isMessageType()) {
self.wrappers_[fieldNumber] = value;
self.extensionObject_[fieldNumber] = value ? value.toArray() : value;
self.extensionObject_[fieldNumber] =
value ? /** @type {!jspb.Message} */ (value).toArray() : value;
} else {
self.extensionObject_[fieldNumber] = value;
}
......@@ -1530,9 +1515,15 @@ jspb.Message.compareFields = function(field1, field2) {
// If the fields are trivially equal, they're equal.
if (field1 == field2) return true;
// If the fields aren't trivially equal and one of them isn't an object,
// they can't possibly be equal.
if (!goog.isObject(field1) || !goog.isObject(field2)) {
// NaN != NaN so we cover this case.
if ((goog.isNumber(field1) && isNaN(field1)) ||
(goog.isNumber(field2) && isNaN(field2))) {
// One of the fields might be a string 'NaN'.
return String(field1) == String(field2);
}
// If the fields aren't trivially equal and one of them isn't an object,
// they can't possibly be equal.
return false;
}
......@@ -1555,24 +1546,26 @@ jspb.Message.compareFields = function(field1, field2) {
// If they're both Arrays, compare them element by element except for the
// optional extension objects at the end, which we compare separately.
if (field1.constructor === Array) {
var typedField1 = /** @type {!Array<?>} */ (field1);
var typedField2 = /** @type {!Array<?>} */ (field2);
var extension1 = undefined;
var extension2 = undefined;
var length = Math.max(field1.length, field2.length);
var length = Math.max(typedField1.length, typedField2.length);
for (var i = 0; i < length; i++) {
var val1 = field1[i];
var val2 = field2[i];
var val1 = typedField1[i];
var val2 = typedField2[i];
if (val1 && (val1.constructor == Object)) {
goog.asserts.assert(extension1 === undefined);
goog.asserts.assert(i === field1.length - 1);
goog.asserts.assert(i === typedField1.length - 1);
extension1 = val1;
val1 = undefined;
}
if (val2 && (val2.constructor == Object)) {
goog.asserts.assert(extension2 === undefined);
goog.asserts.assert(i === field2.length - 1);
goog.asserts.assert(i === typedField2.length - 1);
extension2 = val2;
val2 = undefined;
}
......@@ -1695,8 +1688,13 @@ jspb.Message.clone_ = function(obj) {
var clonedArray = new Array(obj.length);
// Use array iteration where possible because it is faster than for-in.
for (var i = 0; i < obj.length; i++) {
if ((o = obj[i]) != null) {
clonedArray[i] = typeof o == 'object' ? jspb.Message.clone_(o) : o;
o = obj[i];
if (o != null) {
// NOTE:redundant null check existing for NTI compatibility.
// see b/70515949
clonedArray[i] = (typeof o == 'object') ?
jspb.Message.clone_(goog.asserts.assert(o)) :
o;
}
}
return clonedArray;
......@@ -1706,8 +1704,13 @@ jspb.Message.clone_ = function(obj) {
}
var clone = {};
for (var key in obj) {
if ((o = obj[key]) != null) {
clone[key] = typeof o == 'object' ? jspb.Message.clone_(o) : o;
o = obj[key];
if (o != null) {
// NOTE:redundant null check existing for NTI compatibility.
// see b/70515949
clone[key] = (typeof o == 'object') ?
jspb.Message.clone_(goog.asserts.assert(o)) :
o;
}
}
return clone;
......@@ -1723,6 +1726,9 @@ jspb.Message.registerMessageType = function(id, constructor) {
jspb.Message.registry_[id] = constructor;
// This is needed so we can later access messageId directly on the contructor,
// otherwise it is not available due to 'property collapsing' by the compiler.
/**
* @suppress {strictMissingProperties} messageId is not defined on Function
*/
constructor.messageId = id;
};
......
......@@ -418,6 +418,18 @@ describe('Message test suite', function() {
['hi',,, {100: [{200: 'a'}]}], ['hi', {100: [{200: 'a'}]}]));
});
it('testEqualsNonFinite', function() {
assertTrue(jspb.Message.compareFields(NaN, NaN));
assertTrue(jspb.Message.compareFields(NaN, 'NaN'));
assertTrue(jspb.Message.compareFields('NaN', NaN));
assertTrue(jspb.Message.compareFields(Infinity, Infinity));
assertTrue(jspb.Message.compareFields(Infinity, 'Infinity'));
assertTrue(jspb.Message.compareFields('-Infinity', -Infinity));
assertTrue(jspb.Message.compareFields([NaN], ['NaN']));
assertFalse(jspb.Message.compareFields(undefined, NaN));
assertFalse(jspb.Message.compareFields(NaN, undefined));
});
it('testToMap', function() {
var p1 = new proto.jspb.test.Simple1(['k', ['v']]);
var p2 = new proto.jspb.test.Simple1(['k1', ['v1', 'v2']]);
......
This diff is collapsed.
......@@ -37,8 +37,8 @@ argument tuples.
A simple example:
class AdditionExample(parameterized.ParameterizedTestCase):
@parameterized.Parameters(
class AdditionExample(parameterized.TestCase):
@parameterized.parameters(
(1, 2, 3),
(4, 5, 9),
(1, 1, 3))
......@@ -54,8 +54,8 @@ fail due to an assertion error (1 + 1 != 3).
Parameters for invididual test cases can be tuples (with positional parameters)
or dictionaries (with named parameters):
class AdditionExample(parameterized.ParameterizedTestCase):
@parameterized.Parameters(
class AdditionExample(parameterized.TestCase):
@parameterized.parameters(
{'op1': 1, 'op2': 2, 'result': 3},
{'op1': 4, 'op2': 5, 'result': 9},
)
......@@ -77,13 +77,13 @@ stay the same across several invocations, object representations like
'<__main__.Foo object at 0x23d8610>'
are turned into '<__main__.Foo>'. For even more descriptive names,
especially in test logs, you can use the NamedParameters decorator. In
especially in test logs, you can use the named_parameters decorator. In
this case, only tuples are supported, and the first parameters has to
be a string (or an object that returns an apt name when converted via
str()):
class NamedExample(parameterized.ParameterizedTestCase):
@parameterized.NamedParameters(
class NamedExample(parameterized.TestCase):
@parameterized.named_parameters(
('Normal', 'aa', 'aaa', True),
('EmptyPrefix', '', 'abc', True),
('BothEmpty', '', '', True))
......@@ -103,13 +103,13 @@ from the command line:
Parameterized Classes
=====================
If invocation arguments are shared across test methods in a single
ParameterizedTestCase class, instead of decorating all test methods
TestCase class, instead of decorating all test methods
individually, the class itself can be decorated:
@parameterized.Parameters(
@parameterized.parameters(
(1, 2, 3)
(4, 5, 9))
class ArithmeticTest(parameterized.ParameterizedTestCase):
class ArithmeticTest(parameterized.TestCase):
def testAdd(self, arg1, arg2, result):
self.assertEqual(arg1 + arg2, result)
......@@ -122,8 +122,8 @@ If parameters should be shared across several test cases, or are dynamically
created from other sources, a single non-tuple iterable can be passed into
the decorator. This iterable will be used to obtain the test cases:
class AdditionExample(parameterized.ParameterizedTestCase):
@parameterized.Parameters(
class AdditionExample(parameterized.TestCase):
@parameterized.parameters(
c.op1, c.op2, c.result for c in testcases
)
def testAddition(self, op1, op2, result):
......@@ -135,8 +135,8 @@ Single-Argument Test Methods
If a test method takes only one argument, the single argument does not need to
be wrapped into a tuple:
class NegativeNumberExample(parameterized.ParameterizedTestCase):
@parameterized.Parameters(
class NegativeNumberExample(parameterized.TestCase):
@parameterized.parameters(
-1, -3, -4, -5
)
def testIsNegative(self, arg):
......@@ -212,7 +212,7 @@ class _ParameterizedTestIter(object):
def __call__(self, *args, **kwargs):
raise RuntimeError('You appear to be running a parameterized test case '
'without having inherited from parameterized.'
'ParameterizedTestCase. This is bad because none of '
'TestCase. This is bad because none of '
'your test cases are actually being run.')
def __iter__(self):
......@@ -306,7 +306,7 @@ def _ParameterDecorator(naming_type, testcases):
return _Apply
def Parameters(*testcases):
def parameters(*testcases): # pylint: disable=invalid-name
"""A decorator for creating parameterized tests.
See the module docstring for a usage example.
......@@ -321,7 +321,7 @@ def Parameters(*testcases):
return _ParameterDecorator(_ARGUMENT_REPR, testcases)
def NamedParameters(*testcases):
def named_parameters(*testcases): # pylint: disable=invalid-name
"""A decorator for creating parameterized tests.
See the module docstring for a usage example. The first element of
......@@ -348,7 +348,7 @@ class TestGeneratorMetaclass(type):
up as tests by the unittest framework.
In general, it is supposed to be used in conjunction with the
Parameters decorator.
parameters decorator.
"""
def __new__(mcs, class_name, bases, dct):
......@@ -385,8 +385,8 @@ def _UpdateClassDictForParamTestCase(dct, id_suffix, name, iterator):
id_suffix[new_name] = getattr(func, '__x_extra_id__', '')
class ParameterizedTestCase(unittest.TestCase):
"""Base class for test cases using the Parameters decorator."""
class TestCase(unittest.TestCase):
"""Base class for test cases using the parameters decorator."""
__metaclass__ = TestGeneratorMetaclass
def _OriginalName(self):
......@@ -409,10 +409,10 @@ class ParameterizedTestCase(unittest.TestCase):
self._id_suffix.get(self._testMethodName, ''))
def CoopParameterizedTestCase(other_base_class):
def CoopTestCase(other_base_class):
"""Returns a new base class with a cooperative metaclass base.
This enables the ParameterizedTestCase to be used in combination
This enables the TestCase to be used in combination
with other base classes that have custom metaclasses, such as
mox.MoxTestBase.
......@@ -425,7 +425,7 @@ def CoopParameterizedTestCase(other_base_class):
from google3.testing.pybase import parameterized
class ExampleTest(parameterized.CoopParameterizedTestCase(mox.MoxTestBase)):
class ExampleTest(parameterized.CoopTestCase(mox.MoxTestBase)):
...
Args:
......@@ -439,5 +439,5 @@ def CoopParameterizedTestCase(other_base_class):
(other_base_class.__metaclass__,
TestGeneratorMetaclass), {})
return metaclass(
'CoopParameterizedTestCase',
(other_base_class, ParameterizedTestCase), {})
'CoopTestCase',
(other_base_class, TestCase), {})
......@@ -66,10 +66,13 @@ if _api_version < 0: # Still unspecified?
from google.protobuf.internal import use_pure_python
del use_pure_python # Avoids a pylint error and namespace pollution.
except ImportError:
if _proto_extension_modules_exist_in_build:
if sys.version_info[0] >= 3: # Python 3 defaults to C++ impl v2.
_api_version = 2
# TODO(b/17427486): Make Python 2 default to C++ impl v2.
# TODO(b/74017912): It's unsafe to enable :use_fast_cpp_protos by default;
# it can cause data loss if you have any Python-only extensions to any
# message passed back and forth with C++ code.
#
# TODO(b/17427486): Once that bug is fixed, we want to make both Python 2
# and Python 3 default to `_api_version = 2` (C++ implementation V2).
pass
_default_implementation_type = (
'python' if _api_version <= 0 else 'cpp')
......
......@@ -372,7 +372,7 @@ def MapSizer(field_descriptor, is_message_map):
def _VarintEncoder():
"""Return an encoder for a basic varint value (does not include tag)."""
def EncodeVarint(write, value, unused_deterministic):
def EncodeVarint(write, value, unused_deterministic=None):
bits = value & 0x7f
value >>= 7
while value:
......@@ -388,7 +388,7 @@ def _SignedVarintEncoder():
"""Return an encoder for a basic signed varint value (does not include
tag)."""
def EncodeSignedVarint(write, value, unused_deterministic):
def EncodeSignedVarint(write, value, unused_deterministic=None):
if value < 0:
value += (1 << 64)
bits = value & 0x7f
......@@ -524,14 +524,14 @@ def _StructPackEncoder(wire_type, format):
return EncodePackedField
elif is_repeated:
tag_bytes = TagBytes(field_number, wire_type)
def EncodeRepeatedField(write, value, unused_deterministic):
def EncodeRepeatedField(write, value, unused_deterministic=None):
for element in value:
write(tag_bytes)
write(local_struct_pack(format, element))
return EncodeRepeatedField
else:
tag_bytes = TagBytes(field_number, wire_type)
def EncodeField(write, value, unused_deterministic):
def EncodeField(write, value, unused_deterministic=None):
write(tag_bytes)
return write(local_struct_pack(format, value))
return EncodeField
......@@ -595,7 +595,7 @@ def _FloatingPointEncoder(wire_type, format):
return EncodePackedField
elif is_repeated:
tag_bytes = TagBytes(field_number, wire_type)
def EncodeRepeatedField(write, value, unused_deterministic):
def EncodeRepeatedField(write, value, unused_deterministic=None):
for element in value:
write(tag_bytes)
try:
......@@ -605,7 +605,7 @@ def _FloatingPointEncoder(wire_type, format):
return EncodeRepeatedField
else:
tag_bytes = TagBytes(field_number, wire_type)
def EncodeField(write, value, unused_deterministic):
def EncodeField(write, value, unused_deterministic=None):
write(tag_bytes)
try:
write(local_struct_pack(format, value))
......@@ -662,7 +662,7 @@ def BoolEncoder(field_number, is_repeated, is_packed):
return EncodePackedField
elif is_repeated:
tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_VARINT)
def EncodeRepeatedField(write, value, unused_deterministic):
def EncodeRepeatedField(write, value, unused_deterministic=None):
for element in value:
write(tag_bytes)
if element:
......@@ -672,7 +672,7 @@ def BoolEncoder(field_number, is_repeated, is_packed):
return EncodeRepeatedField
else:
tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_VARINT)
def EncodeField(write, value, unused_deterministic):
def EncodeField(write, value, unused_deterministic=None):
write(tag_bytes)
if value:
return write(true_byte)
......
......@@ -983,6 +983,18 @@ class JsonFormatTest(JsonFormatBase):
self.assertEqual('{\n"int32Value": 12345\n}',
json_format.MessageToJson(message, indent=0))
def testFormatEnumsAsInts(self):
message = json_format_proto3_pb2.TestMessage()
message.enum_value = json_format_proto3_pb2.BAR
message.repeated_enum_value.append(json_format_proto3_pb2.FOO)
message.repeated_enum_value.append(json_format_proto3_pb2.BAR)
self.assertEqual(json.loads('{\n'
' "enumValue": 1,\n'
' "repeatedEnumValue": [0, 1]\n'
'}\n'),
json.loads(json_format.MessageToJson(
message, use_integers_for_enums=True)))
def testParseDict(self):
expected = 12345
js_dict = {'int32Value': expected}
......
......@@ -99,7 +99,7 @@ def IsNegInf(val):
BaseTestCase = testing_refleaks.BaseTestCase
@_parameterized.NamedParameters(
@_parameterized.named_parameters(
('_proto2', unittest_pb2),
('_proto3', unittest_proto3_arena_pb2))
class MessageTest(BaseTestCase):
......@@ -1694,6 +1694,33 @@ class Proto3Test(BaseTestCase):
with self.assertRaises(TypeError):
del msg2.map_int32_foreign_message['']
def testMapMergeFrom(self):
msg = map_unittest_pb2.TestMap()
msg.map_int32_int32[12] = 34
msg.map_int32_int32[56] = 78
msg.map_int64_int64[22] = 33
msg.map_int32_foreign_message[111].c = 5
msg.map_int32_foreign_message[222].c = 10
msg2 = map_unittest_pb2.TestMap()
msg2.map_int32_int32[12] = 55
msg2.map_int64_int64[88] = 99
msg2.map_int32_foreign_message[222].c = 15
msg2.map_int32_foreign_message[222].d = 20
msg2.map_int32_int32.MergeFrom(msg.map_int32_int32)
self.assertEqual(34, msg2.map_int32_int32[12])
self.assertEqual(78, msg2.map_int32_int32[56])
msg2.map_int64_int64.MergeFrom(msg.map_int64_int64)
self.assertEqual(33, msg2.map_int64_int64[22])
self.assertEqual(99, msg2.map_int64_int64[88])
msg2.map_int32_foreign_message.MergeFrom(msg.map_int32_foreign_message)
self.assertEqual(5, msg2.map_int32_foreign_message[111].c)
self.assertEqual(10, msg2.map_int32_foreign_message[222].c)
self.assertFalse(msg2.map_int32_foreign_message[222].HasField('d'))
def testMergeFromBadType(self):
msg = map_unittest_pb2.TestMap()
with self.assertRaisesRegexp(
......
syntax = "proto2";
option py_api_version = 2;
enum NoPackageEnum {
NO_PACKAGE_VALUE_0 = 0;
NO_PACKAGE_VALUE_1 = 1;
}
message NoPackageMessage {
optional NoPackageEnum no_package_enum = 1;
}
\ No newline at end of file
......@@ -48,6 +48,7 @@ except ImportError:
from google.protobuf.internal import _parameterized
from google.protobuf import any_pb2
from google.protobuf import any_test_pb2
from google.protobuf import map_unittest_pb2
from google.protobuf import unittest_mset_pb2
......@@ -99,7 +100,7 @@ class TextFormatBase(unittest.TestCase):
return text
@_parameterized.Parameters((unittest_pb2), (unittest_proto3_arena_pb2))
@_parameterized.parameters((unittest_pb2), (unittest_proto3_arena_pb2))
class TextFormatTest(TextFormatBase):
def testPrintExotic(self, message_module):
......@@ -369,6 +370,7 @@ class TextFormatTest(TextFormatBase):
def testParseRepeatedScalarShortFormat(self, message_module):
message = message_module.TestAllTypes()
text = ('repeated_int64: [100, 200];\n'
'repeated_int64: []\n'
'repeated_int64: 300,\n'
'repeated_string: ["one", "two"];\n')
text_format.Parse(text, message)
......@@ -524,20 +526,68 @@ class OnlyWorksWithProto2RightNowTests(TextFormatBase):
def testPrintInIndexOrder(self):
message = unittest_pb2.TestFieldOrderings()
message.my_string = '115'
# Fields are listed in index order instead of field number.
message.my_string = 'str'
message.my_int = 101
message.my_float = 111
message.optional_nested_message.oo = 0
message.optional_nested_message.bb = 1
message.Extensions[unittest_pb2.my_extension_string] = 'ext_str0'
# Extensions are listed based on the order of extension number.
# Extension number 12.
message.Extensions[unittest_pb2.TestExtensionOrderings2.
test_ext_orderings2].my_string = 'ext_str2'
# Extension number 13.
message.Extensions[unittest_pb2.TestExtensionOrderings1.
test_ext_orderings1].my_string = 'ext_str1'
# Extension number 14.
message.Extensions[
unittest_pb2.TestExtensionOrderings2.TestExtensionOrderings3.
test_ext_orderings3].my_string = 'ext_str3'
# Print in index order.
self.CompareToGoldenText(
self.RemoveRedundantZeros(text_format.MessageToString(
message, use_index_order=True)),
'my_string: \"115\"\nmy_int: 101\nmy_float: 111\n'
'optional_nested_message {\n oo: 0\n bb: 1\n}\n')
self.RemoveRedundantZeros(
text_format.MessageToString(message, use_index_order=True)),
'my_string: "str"\n'
'my_int: 101\n'
'my_float: 111\n'
'optional_nested_message {\n'
' oo: 0\n'
' bb: 1\n'
'}\n'
'[protobuf_unittest.TestExtensionOrderings2.test_ext_orderings2] {\n'
' my_string: "ext_str2"\n'
'}\n'
'[protobuf_unittest.TestExtensionOrderings1.test_ext_orderings1] {\n'
' my_string: "ext_str1"\n'
'}\n'
'[protobuf_unittest.TestExtensionOrderings2.TestExtensionOrderings3'
'.test_ext_orderings3] {\n'
' my_string: "ext_str3"\n'
'}\n'
'[protobuf_unittest.my_extension_string]: "ext_str0"\n')
# By default, print in field number order.
self.CompareToGoldenText(
self.RemoveRedundantZeros(text_format.MessageToString(message)),
'my_int: 101\nmy_string: \"115\"\nmy_float: 111\n'
'optional_nested_message {\n bb: 1\n oo: 0\n}\n')
'my_int: 101\n'
'my_string: "str"\n'
'[protobuf_unittest.TestExtensionOrderings2.test_ext_orderings2] {\n'
' my_string: "ext_str2"\n'
'}\n'
'[protobuf_unittest.TestExtensionOrderings1.test_ext_orderings1] {\n'
' my_string: "ext_str1"\n'
'}\n'
'[protobuf_unittest.TestExtensionOrderings2.TestExtensionOrderings3'
'.test_ext_orderings3] {\n'
' my_string: "ext_str3"\n'
'}\n'
'[protobuf_unittest.my_extension_string]: "ext_str0"\n'
'my_float: 111\n'
'optional_nested_message {\n'
' bb: 1\n'
' oo: 0\n'
'}\n')
def testMergeLinesGolden(self):
opened = self.ReadGolden('text_format_unittest_data_oneof_implemented.txt')
......@@ -970,15 +1020,26 @@ class Proto2Tests(TextFormatBase):
'"protobuf_unittest.optional_int32_extension" extensions.'),
text_format.Parse, text, message)
def testParseDuplicateNestedMessageScalars(self):
def testParseDuplicateMessages(self):
message = unittest_pb2.TestAllTypes()
text = ('optional_nested_message { bb: 1 } '
'optional_nested_message { bb: 2 }')
six.assertRaisesRegex(self, text_format.ParseError, (
'1:65 : Message type "protobuf_unittest.TestAllTypes.NestedMessage" '
'should not have multiple "bb" fields.'), text_format.Parse, text,
'1:59 : Message type "protobuf_unittest.TestAllTypes" '
'should not have multiple "optional_nested_message" fields.'),
text_format.Parse, text,
message)
def testParseDuplicateExtensionMessages(self):
message = unittest_pb2.TestAllExtensions()
text = ('[protobuf_unittest.optional_nested_message_extension]: {} '
'[protobuf_unittest.optional_nested_message_extension]: {}')
six.assertRaisesRegex(self, text_format.ParseError, (
'1:114 : Message type "protobuf_unittest.TestAllExtensions" '
'should not have multiple '
'"protobuf_unittest.optional_nested_message_extension" extensions.'),
text_format.Parse, text, message)
def testParseDuplicateScalars(self):
message = unittest_pb2.TestAllTypes()
text = ('optional_int32: 42 ' 'optional_int32: 67')
......@@ -1065,6 +1126,14 @@ class Proto3Tests(unittest.TestCase):
' }\n'
'}\n')
def testTopAnyMessage(self):
packed_msg = unittest_pb2.OneString()
msg = any_pb2.Any()
msg.Pack(packed_msg)
text = text_format.MessageToString(msg)
other_msg = text_format.Parse(text, any_pb2.Any())
self.assertEqual(msg, other_msg)
def testPrintMessageExpandAnyRepeated(self):
packed_message = unittest_pb2.OneString()
message = any_test_pb2.TestAny()
......@@ -1489,7 +1558,7 @@ class TokenizerTest(unittest.TestCase):
# Tests for pretty printer functionality.
@_parameterized.Parameters((unittest_pb2), (unittest_proto3_arena_pb2))
@_parameterized.parameters((unittest_pb2), (unittest_proto3_arena_pb2))
class PrettyPrinterTest(TextFormatBase):
def testPrettyPrintNoMatch(self, message_module):
......
......@@ -375,6 +375,9 @@ def _CheckDurationValid(seconds, nanos):
raise Error(
'Duration is not valid: Nanos {0} must be in range '
'[-999999999, 999999999].'.format(nanos))
if (nanos < 0 and seconds > 0) or (nanos > 0 and seconds < 0):
raise Error(
'Duration is not valid: Sign mismatch.')
def _RoundTowardZero(value, divider):
......@@ -649,9 +652,10 @@ def _MergeMessage(
raise ValueError('Error: Field {0} in message {1} is not a singular '
'message field and cannot have sub-fields.'.format(
name, source_descriptor.full_name))
_MergeMessage(
child, getattr(source, name), getattr(destination, name),
replace_message, replace_repeated)
if source.HasField(name):
_MergeMessage(
child, getattr(source, name), getattr(destination, name),
replace_message, replace_repeated)
continue
if field.label == FieldDescriptor.LABEL_REPEATED:
if replace_repeated:
......
......@@ -345,6 +345,12 @@ class TimeUtilTest(TimeUtilTestBase):
r'Duration is not valid\: Nanos 1000000000 must be in range'
r' \[-999999999\, 999999999\].',
message.ToJsonString)
message.seconds = -1
message.nanos = 1
self.assertRaisesRegexp(
well_known_types.Error,
r'Duration is not valid\: Sign mismatch.',
message.ToJsonString)
class FieldMaskTest(unittest.TestCase):
......@@ -599,6 +605,16 @@ class FieldMaskTest(unittest.TestCase):
self.assertEqual(1, len(nested_dst.payload.repeated_int32))
self.assertEqual(1234, nested_dst.payload.repeated_int32[0])
# Test Merge oneof field.
new_msg = unittest_pb2.TestOneof2()
dst = unittest_pb2.TestOneof2()
dst.foo_message.qux_int = 1
mask = field_mask_pb2.FieldMask()
mask.FromJsonString('fooMessage,fooLazyMessage.quxInt')
mask.MergeMessage(new_msg, dst)
self.assertTrue(dst.HasField('foo_message'))
self.assertFalse(dst.HasField('foo_lazy_message'))
def testMergeErrors(self):
src = unittest_pb2.TestAllTypes()
dst = unittest_pb2.TestAllTypes()
......
......@@ -42,21 +42,28 @@ Simple usage example:
__author__ = 'jieluo@google.com (Jie Luo)'
# pylint: disable=g-statement-before-imports,g-import-not-at-top
try:
from collections import OrderedDict
except ImportError:
from ordereddict import OrderedDict #PY26
from ordereddict import OrderedDict # PY26
# pylint: enable=g-statement-before-imports,g-import-not-at-top
import base64
import json
import math
from operator import methodcaller
import re
import six
import sys
from operator import methodcaller
import six
from google.protobuf import descriptor
from google.protobuf import symbol_database
_TIMESTAMPFOMAT = '%Y-%m-%dT%H:%M:%S'
_INT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_INT32,
descriptor.FieldDescriptor.CPPTYPE_UINT32,
......@@ -93,7 +100,8 @@ def MessageToJson(message,
including_default_value_fields=False,
preserving_proto_field_name=False,
indent=2,
sort_keys=False):
sort_keys=False,
use_integers_for_enums=False):
"""Converts protobuf message to JSON format.
Args:
......@@ -108,18 +116,21 @@ def MessageToJson(message,
indent: The JSON object will be pretty-printed with this indent level.
An indent level of 0 or negative will only insert newlines.
sort_keys: If True, then the output will be sorted by field names.
use_integers_for_enums: If true, print integers instead of enum names.
Returns:
A string containing the JSON formatted protocol buffer message.
"""
printer = _Printer(including_default_value_fields,
preserving_proto_field_name)
preserving_proto_field_name,
use_integers_for_enums)
return printer.ToJsonString(message, indent, sort_keys)
def MessageToDict(message,
including_default_value_fields=False,
preserving_proto_field_name=False):
preserving_proto_field_name=False,
use_integers_for_enums=False):
"""Converts protobuf message to a dictionary.
When the dictionary is encoded to JSON, it conforms to proto3 JSON spec.
......@@ -133,12 +144,14 @@ def MessageToDict(message,
preserving_proto_field_name: If True, use the original proto field
names as defined in the .proto file. If False, convert the field
names to lowerCamelCase.
use_integers_for_enums: If true, print integers instead of enum names.
Returns:
A dict representation of the protocol buffer message.
"""
printer = _Printer(including_default_value_fields,
preserving_proto_field_name)
preserving_proto_field_name,
use_integers_for_enums)
# pylint: disable=protected-access
return printer._MessageToJsonObject(message)
......@@ -154,9 +167,11 @@ class _Printer(object):
def __init__(self,
including_default_value_fields=False,
preserving_proto_field_name=False):
preserving_proto_field_name=False,
use_integers_for_enums=False):
self.including_default_value_fields = including_default_value_fields
self.preserving_proto_field_name = preserving_proto_field_name
self.use_integers_for_enums = use_integers_for_enums
def ToJsonString(self, message, indent, sort_keys):
js = self._MessageToJsonObject(message)
......@@ -247,6 +262,8 @@ class _Printer(object):
if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
return self._MessageToJsonObject(value)
elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
if self.use_integers_for_enums:
return value
enum_value = field.enum_type.values_by_number.get(value, None)
if enum_value is not None:
return enum_value.name
......
......@@ -188,38 +188,35 @@ const FileDescriptor* GetFileDescriptor(const MethodDescriptor* descriptor) {
// Always returns a new reference.
template<class DescriptorClass>
static PyObject* GetOrBuildOptions(const DescriptorClass *descriptor) {
// Options (and their extensions) are completely resolved in the proto file
// containing the descriptor.
PyDescriptorPool* pool = GetDescriptorPool_FromPool(
// Options are cached in the pool that owns the descriptor.
// First search in the cache.
PyDescriptorPool* caching_pool = GetDescriptorPool_FromPool(
GetFileDescriptor(descriptor)->pool());
hash_map<const void*, PyObject*>* descriptor_options =
pool->descriptor_options;
// First search in the cache.
caching_pool->descriptor_options;
if (descriptor_options->find(descriptor) != descriptor_options->end()) {
PyObject *value = (*descriptor_options)[descriptor];
Py_INCREF(value);
return value;
}
// Similar to the C++ implementation, we return an Options object from the
// default (generated) factory, so that client code know that they can use
// extensions from generated files:
// d.GetOptions().Extensions[some_pb2.extension]
//
// The consequence is that extensions not defined in the default pool won't
// be available. If needed, we could add an optional 'message_factory'
// parameter to the GetOptions() function.
PyMessageFactory* message_factory =
GetDefaultDescriptorPool()->py_message_factory;
// Build the Options object: get its Python class, and make a copy of the C++
// read-only instance.
const Message& options(descriptor->options());
const Descriptor *message_type = options.GetDescriptor();
PyMessageFactory* message_factory = pool->py_message_factory;
CMessageClass* message_class = message_factory::GetMessageClass(
CMessageClass* message_class = message_factory::GetOrCreateMessageClass(
message_factory, message_type);
if (message_class == NULL) {
// The Options message was not found in the current DescriptorPool.
// This means that the pool cannot contain any extensions to the Options
// message either, so falling back to the basic pool we can only increase
// the chances of successfully parsing the options.
PyErr_Clear();
pool = GetDefaultDescriptorPool();
message_factory = pool->py_message_factory;
message_class = message_factory::GetMessageClass(
message_factory, message_type);
}
if (message_class == NULL) {
PyErr_Format(PyExc_TypeError, "Could not retrieve class for Options: %s",
message_type->full_name().c_str());
......@@ -248,7 +245,8 @@ static PyObject* GetOrBuildOptions(const DescriptorClass *descriptor) {
options.SerializeToString(&serialized);
io::CodedInputStream input(
reinterpret_cast<const uint8*>(serialized.c_str()), serialized.size());
input.SetExtensionRegistry(pool->pool, message_factory->message_factory);
input.SetExtensionRegistry(message_factory->pool->pool,
message_factory->message_factory);
bool success = cmsg->message->MergePartialFromCodedStream(&input);
if (!success) {
PyErr_Format(PyExc_ValueError, "Error parsing Options message");
......@@ -564,6 +562,11 @@ static int SetOptions(PyBaseDescriptor *self, PyObject *value,
return CheckCalledFromGeneratedFile("_options");
}
static int SetSerializedOptions(PyBaseDescriptor *self, PyObject *value,
void *closure) {
return CheckCalledFromGeneratedFile("_serialized_options");
}
static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) {
return CopyToPythonProto<DescriptorProto>(_GetDescriptor(self), target);
}
......@@ -623,6 +626,8 @@ static PyGetSetDef Getters[] = {
{ "is_extendable", (getter)IsExtendable, (setter)NULL},
{ "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
{ "_options", (getter)NULL, (setter)SetOptions, "Options"},
{ "_serialized_options", (getter)NULL, (setter)SetSerializedOptions,
"Serialized Options"},
{ "syntax", (getter)GetSyntax, (setter)NULL, "Syntax"},
{NULL}
};
......@@ -785,7 +790,7 @@ static PyObject* GetDefaultValue(PyBaseDescriptor *self, void *closure) {
break;
}
case FieldDescriptor::CPPTYPE_STRING: {
string value = _GetDescriptor(self)->default_value_string();
const string& value = _GetDescriptor(self)->default_value_string();
result = ToStringObject(_GetDescriptor(self), value);
break;
}
......@@ -897,6 +902,10 @@ static int SetOptions(PyBaseDescriptor *self, PyObject *value,
return CheckCalledFromGeneratedFile("_options");
}
static int SetSerializedOptions(PyBaseDescriptor *self, PyObject *value,
void *closure) {
return CheckCalledFromGeneratedFile("_serialized_options");
}
static PyGetSetDef Getters[] = {
{ "full_name", (getter)GetFullName, NULL, "Full name"},
......@@ -926,6 +935,8 @@ static PyGetSetDef Getters[] = {
"Containing oneof"},
{ "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
{ "_options", (getter)NULL, (setter)SetOptions, "Options"},
{ "_serialized_options", (getter)NULL, (setter)SetSerializedOptions,
"Serialized Options"},
{NULL}
};
......@@ -1055,6 +1066,11 @@ static int SetOptions(PyBaseDescriptor *self, PyObject *value,
return CheckCalledFromGeneratedFile("_options");
}
static int SetSerializedOptions(PyBaseDescriptor *self, PyObject *value,
void *closure) {
return CheckCalledFromGeneratedFile("_serialized_options");
}
static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) {
return CopyToPythonProto<EnumDescriptorProto>(_GetDescriptor(self), target);
}
......@@ -1079,6 +1095,8 @@ static PyGetSetDef Getters[] = {
"Containing type"},
{ "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
{ "_options", (getter)NULL, (setter)SetOptions, "Options"},
{ "_serialized_options", (getter)NULL, (setter)SetSerializedOptions,
"Serialized Options"},
{NULL}
};
......@@ -1179,6 +1197,10 @@ static int SetOptions(PyBaseDescriptor *self, PyObject *value,
return CheckCalledFromGeneratedFile("_options");
}
static int SetSerializedOptions(PyBaseDescriptor *self, PyObject *value,
void *closure) {
return CheckCalledFromGeneratedFile("_serialized_options");
}
static PyGetSetDef Getters[] = {
{ "name", (getter)GetName, NULL, "name"},
......@@ -1188,6 +1210,8 @@ static PyGetSetDef Getters[] = {
{ "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
{ "_options", (getter)NULL, (setter)SetOptions, "Options"},
{ "_serialized_options", (getter)NULL, (setter)SetSerializedOptions,
"Serialized Options"},
{NULL}
};
......@@ -1330,6 +1354,11 @@ static int SetOptions(PyFileDescriptor *self, PyObject *value,
return CheckCalledFromGeneratedFile("_options");
}
static int SetSerializedOptions(PyFileDescriptor *self, PyObject *value,
void *closure) {
return CheckCalledFromGeneratedFile("_serialized_options");
}
static PyObject* GetSyntax(PyFileDescriptor *self, void *closure) {
return PyString_InternFromString(
FileDescriptor::SyntaxName(_GetDescriptor(self)->syntax()));
......@@ -1355,6 +1384,8 @@ static PyGetSetDef Getters[] = {
{ "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
{ "_options", (getter)NULL, (setter)SetOptions, "Options"},
{ "_serialized_options", (getter)NULL, (setter)SetSerializedOptions,
"Serialized Options"},
{ "syntax", (getter)GetSyntax, (setter)NULL, "Syntax"},
{NULL}
};
......@@ -1500,6 +1531,11 @@ static int SetOptions(PyBaseDescriptor *self, PyObject *value,
return CheckCalledFromGeneratedFile("_options");
}
static int SetSerializedOptions(PyBaseDescriptor *self, PyObject *value,
void *closure) {
return CheckCalledFromGeneratedFile("_serialized_options");
}
static PyGetSetDef Getters[] = {
{ "name", (getter)GetName, NULL, "Name"},
{ "full_name", (getter)GetFullName, NULL, "Full name"},
......@@ -1508,6 +1544,8 @@ static PyGetSetDef Getters[] = {
{ "containing_type", (getter)GetContainingType, NULL, "Containing type"},
{ "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
{ "_options", (getter)NULL, (setter)SetOptions, "Options"},
{ "_serialized_options", (getter)NULL, (setter)SetSerializedOptions,
"Serialized Options"},
{ "fields", (getter)GetFields, NULL, "Fields"},
{NULL}
};
......
......@@ -33,9 +33,6 @@
#include <google/protobuf/pyext/extension_dict.h>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
......
......@@ -37,9 +37,8 @@
#include <Python.h>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <google/protobuf/pyext/message.h>
namespace google {
namespace protobuf {
......@@ -47,16 +46,8 @@ namespace protobuf {
class Message;
class FieldDescriptor;
#ifdef _SHARED_PTR_H
using std::shared_ptr;
#else
using internal::shared_ptr;
#endif
namespace python {
struct CMessage;
typedef struct ExtensionDict {
PyObject_HEAD;
......@@ -64,7 +55,7 @@ typedef struct ExtensionDict {
// proto tree. Every Python container class holds a
// reference to it in order to keep it alive as long as there's a
// Python object that references any part of the tree.
shared_ptr<Message> owner;
CMessage::OwnerRef owner;
// Weak reference to parent message. Used to make sure
// the parent is writable when an extension field is modified.
......
......@@ -33,9 +33,6 @@
#include <google/protobuf/pyext/map_container.h>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
......@@ -76,7 +73,7 @@ class MapReflectionFriend {
struct MapIterator {
PyObject_HEAD;
google::protobuf::scoped_ptr< ::google::protobuf::MapIterator> iter;
std::unique_ptr<::google::protobuf::MapIterator> iter;
// A pointer back to the container, so we can notice changes to the version.
// We own a ref on this.
......@@ -94,7 +91,7 @@ struct MapIterator {
// as this iterator does. This is solely for the benefit of the MapIterator
// destructor -- we should never actually access the iterator in this state
// except to delete it.
shared_ptr<Message> owner;
CMessage::OwnerRef owner;
// The version of the map when we took the iterator to it.
//
......@@ -339,6 +336,24 @@ PyObject* GetEntryClass(PyObject* _self) {
return reinterpret_cast<PyObject*>(message_class);
}
PyObject* MergeFrom(PyObject* _self, PyObject* arg) {
MapContainer* self = GetMap(_self);
MapContainer* other_map = GetMap(arg);
Message* message = self->GetMutableMessage();
const Message* other_message = other_map->message;
const Reflection* reflection = message->GetReflection();
const Reflection* other_reflection = other_message->GetReflection();
int count = other_reflection->FieldSize(
*other_message, other_map->parent_field_descriptor);
for (int i = 0 ; i < count; i ++) {
reflection->AddMessage(message, self->parent_field_descriptor)->MergeFrom(
other_reflection->GetRepeatedMessage(
*other_message, other_map->parent_field_descriptor, i));
}
self->version++;
Py_RETURN_NONE;
}
PyObject* MapReflectionFriend::Contains(PyObject* _self, PyObject* key) {
MapContainer* self = GetMap(_self);
......@@ -535,6 +550,8 @@ static PyMethodDef ScalarMapMethods[] = {
"Gets the value for the given key if present, or otherwise a default" },
{ "GetEntryClass", (PyCFunction)GetEntryClass, METH_NOARGS,
"Return the class used to build Entries of (key, value) pairs." },
{ "MergeFrom", (PyCFunction)MergeFrom, METH_O,
"Merges a map into the current map." },
/*
{ "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
"Makes a deep copy of the class." },
......@@ -810,6 +827,8 @@ static PyMethodDef MessageMapMethods[] = {
"Alias for getitem, useful to make explicit that the map is mutated." },
{ "GetEntryClass", (PyCFunction)GetEntryClass, METH_NOARGS,
"Return the class used to build Entries of (key, value) pairs." },
{ "MergeFrom", (PyCFunction)MergeFrom, METH_O,
"Merges a map into the current map." },
/*
{ "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
"Makes a deep copy of the class." },
......
......@@ -34,27 +34,18 @@
#include <Python.h>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
#include <google/protobuf/pyext/message.h>
namespace google {
namespace protobuf {
class Message;
#ifdef _SHARED_PTR_H
using std::shared_ptr;
#else
using internal::shared_ptr;
#endif
namespace python {
struct CMessage;
struct CMessageClass;
// This struct is used directly for ScalarMap, and is the base class of
......@@ -66,7 +57,7 @@ struct MapContainer {
// proto tree. Every Python MapContainer holds a
// reference to it in order to keep it alive as long as there's a
// Python object that references any part of the tree.
shared_ptr<Message> owner;
CMessage::OwnerRef owner;
// Pointer to the C++ Message that contains this container. The
// MapContainer does not own this pointer.
......@@ -99,9 +90,7 @@ struct MapContainer {
int Release();
// Set the owner field of self and any children of self.
void SetOwner(const shared_ptr<Message>& new_owner) {
owner = new_owner;
}
void SetOwner(const CMessage::OwnerRef& new_owner) { owner = new_owner; }
};
struct MessageMapContainer : public MapContainer {
......
......@@ -35,9 +35,6 @@
#include <map>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <string>
#include <vector>
#include <structmember.h> // A Python header file.
......@@ -658,7 +655,7 @@ bool CheckAndGetInteger(PyObject* arg, T* value) {
// Unlike PyLong_AsLongLong, PyLong_AsUnsignedLongLong is very
// picky about the exact type.
PyObject* casted = PyNumber_Long(arg);
if (GOOGLE_PREDICT_FALSE(casted == NULL)) {
if (GOOGLE_PREDICT_FALSE(casted == nullptr)) {
// Propagate existing error.
return false;
}
......@@ -683,7 +680,7 @@ bool CheckAndGetInteger(PyObject* arg, T* value) {
// Valid subclasses of numbers.Integral should have a __long__() method
// so fall back to that.
PyObject* casted = PyNumber_Long(arg);
if (GOOGLE_PREDICT_FALSE(casted == NULL)) {
if (GOOGLE_PREDICT_FALSE(casted == nullptr)) {
// Propagate existing error.
return false;
}
......@@ -830,7 +827,8 @@ bool CheckAndSetString(
return true;
}
PyObject* ToStringObject(const FieldDescriptor* descriptor, string value) {
PyObject* ToStringObject(const FieldDescriptor* descriptor,
const string& value) {
if (descriptor->type() != FieldDescriptor::TYPE_STRING) {
return PyBytes_FromStringAndSize(value.c_str(), value.length());
}
......@@ -1318,6 +1316,8 @@ CMessage* NewEmptyMessage(CMessageClass* type) {
return NULL;
}
// Use "placement new" syntax to initialize the C++ object.
new (&self->owner) CMessage::OwnerRef(NULL);
self->message = NULL;
self->parent = NULL;
self->parent_field_descriptor = NULL;
......@@ -1414,7 +1414,7 @@ static void Dealloc(CMessage* self) {
Py_CLEAR(self->extensions);
Py_CLEAR(self->composite_fields);
self->owner.reset();
self->owner.~ThreadUnsafeSharedPtr<Message>();
Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
}
......@@ -1616,9 +1616,10 @@ PyObject* HasExtension(CMessage* self, PyObject* extension) {
// * Clear the weak references from the released container to the
// parent.
struct SetOwnerVisitor : public ChildVisitor {
class SetOwnerVisitor : public ChildVisitor {
public:
// new_owner must outlive this object.
explicit SetOwnerVisitor(const shared_ptr<Message>& new_owner)
explicit SetOwnerVisitor(const CMessage::OwnerRef& new_owner)
: new_owner_(new_owner) {}
int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) {
......@@ -1642,11 +1643,11 @@ struct SetOwnerVisitor : public ChildVisitor {
}
private:
const shared_ptr<Message>& new_owner_;
const CMessage::OwnerRef& new_owner_;
};
// Change the owner of this CMessage and all its children, recursively.
int SetOwner(CMessage* self, const shared_ptr<Message>& new_owner) {
int SetOwner(CMessage* self, const CMessage::OwnerRef& new_owner) {
self->owner = new_owner;
if (ForEachCompositeField(self, SetOwnerVisitor(new_owner)) == -1)
return -1;
......@@ -1679,7 +1680,7 @@ int ReleaseSubMessage(CMessage* self,
const FieldDescriptor* field_descriptor,
CMessage* child_cmessage) {
// Release the Message
shared_ptr<Message> released_message(ReleaseMessage(
CMessage::OwnerRef released_message(ReleaseMessage(
self, child_cmessage->message->GetDescriptor(), field_descriptor));
child_cmessage->message = released_message.get();
child_cmessage->owner.swap(released_message);
......@@ -2329,7 +2330,9 @@ PyObject* InternalGetScalar(const Message* message,
break;
}
case FieldDescriptor::CPPTYPE_STRING: {
string value = reflection->GetString(*message, field_descriptor);
string scratch;
const string& value =
reflection->GetStringReference(*message, field_descriptor, &scratch);
result = ToStringObject(field_descriptor, value);
break;
}
......
......@@ -37,11 +37,11 @@
#include <Python.h>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/pyext/thread_unsafe_shared_ptr.h>
namespace google {
namespace protobuf {
......@@ -71,7 +71,9 @@ typedef struct CMessage {
// proto tree. Every Python CMessage holds a reference to it in
// order to keep it alive as long as there's a Python object that
// references any part of the tree.
shared_ptr<Message> owner;
typedef ThreadUnsafeSharedPtr<Message> OwnerRef;
OwnerRef owner;
// Weak reference to a parent CMessage object. This is NULL for any top-level
// message and is set for any child message (i.e. a child submessage or a
......@@ -255,7 +257,7 @@ PyObject* FindInitializationErrors(CMessage* self);
// Set the owner field of self and any children of self, recursively.
// Used when self is being released and thus has a new owner (the
// released Message.)
int SetOwner(CMessage* self, const shared_ptr<Message>& new_owner);
int SetOwner(CMessage* self, const CMessage::OwnerRef& new_owner);
int AssureWritable(CMessage* self);
......@@ -336,7 +338,8 @@ bool CheckAndSetString(
const Reflection* reflection,
bool append,
int index);
PyObject* ToStringObject(const FieldDescriptor* descriptor, string value);
PyObject* ToStringObject(const FieldDescriptor* descriptor,
const string& value);
// Check if the passed field descriptor belongs to the given message.
// If not, return false and set a Python exception (a KeyError)
......@@ -347,6 +350,15 @@ extern PyObject* PickleError_class;
bool InitProto2MessageModule(PyObject *m);
#if LANG_CXX11
// These are referenced by repeated_scalar_container, and must
// be explicitly instantiated.
extern template bool CheckAndGetInteger<int32>(PyObject*, int32*);
extern template bool CheckAndGetInteger<int64>(PyObject*, int64*);
extern template bool CheckAndGetInteger<uint32>(PyObject*, uint32*);
extern template bool CheckAndGetInteger<uint64>(PyObject*, uint64*);
#endif
} // namespace python
} // namespace protobuf
......
......@@ -100,7 +100,9 @@ PyObject* New(PyTypeObject* type, PyObject* args, PyObject* kwargs) {
NewMessageFactory(type, reinterpret_cast<PyDescriptorPool*>(pool)));
}
static void Dealloc(PyMessageFactory* self) {
static void Dealloc(PyObject* pself) {
PyMessageFactory* self = reinterpret_cast<PyMessageFactory*>(pself);
// TODO(amauryfa): When the MessageFactory is not created from the
// DescriptorPool this reference should be owned, not borrowed.
// Py_CLEAR(self->pool);
......@@ -111,7 +113,7 @@ static void Dealloc(PyMessageFactory* self) {
}
delete self->classes_by_descriptor;
delete self->message_factory;
Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
Py_TYPE(self)->tp_free(pself);
}
// Add a message class to our database.
......@@ -231,7 +233,7 @@ PyTypeObject PyMessageFactory_Type = {
".MessageFactory", // tp_name
sizeof(PyMessageFactory), // tp_basicsize
0, // tp_itemsize
(destructor)message_factory::Dealloc, // tp_dealloc
message_factory::Dealloc, // tp_dealloc
0, // tp_print
0, // tp_getattr
0, // tp_setattr
......
......@@ -37,27 +37,19 @@
#include <Python.h>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <string>
#include <vector>
#include <google/protobuf/pyext/message.h>
namespace google {
namespace protobuf {
class FieldDescriptor;
class Message;
#ifdef _SHARED_PTR_H
using std::shared_ptr;
#else
using internal::shared_ptr;
#endif
namespace python {
struct CMessage;
struct CMessageClass;
// A RepeatedCompositeContainer can be in one of two states: attached
......@@ -77,7 +69,7 @@ typedef struct RepeatedCompositeContainer {
// proto tree. Every Python RepeatedCompositeContainer holds a
// reference to it in order to keep it alive as long as there's a
// Python object that references any part of the tree.
shared_ptr<Message> owner;
CMessage::OwnerRef owner;
// Weak reference to parent object. May be NULL. Used to make sure
// the parent is writable before modifying the
......@@ -148,11 +140,6 @@ int AssignSubscript(RepeatedCompositeContainer* self,
PyObject* slice,
PyObject* value);
// Releases the messages in the container to the given message.
//
// Returns 0 on success, -1 on failure.
int ReleaseToMessage(RepeatedCompositeContainer* self, Message* new_message);
// Releases the messages in the container to a new message.
//
// Returns 0 on success, -1 on failure.
......@@ -160,7 +147,7 @@ int Release(RepeatedCompositeContainer* self);
// Returns 0 on success, -1 on failure.
int SetOwner(RepeatedCompositeContainer* self,
const shared_ptr<Message>& new_owner);
const CMessage::OwnerRef& new_owner);
// Removes the last element of the repeated message field 'field' on
// the Message 'parent', and transfers the ownership of the released
......
......@@ -37,27 +37,14 @@
#include <Python.h>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <google/protobuf/descriptor.h>
#include <google/protobuf/pyext/message.h>
namespace google {
namespace protobuf {
class Message;
#ifdef _SHARED_PTR_H
using std::shared_ptr;
#else
using internal::shared_ptr;
#endif
namespace python {
struct CMessage;
typedef struct RepeatedScalarContainer {
PyObject_HEAD;
......@@ -65,7 +52,7 @@ typedef struct RepeatedScalarContainer {
// proto tree. Every Python RepeatedScalarContainer holds a
// reference to it in order to keep it alive as long as there's a
// Python object that references any part of the tree.
shared_ptr<Message> owner;
CMessage::OwnerRef owner;
// Pointer to the C++ Message that contains this container. The
// RepeatedScalarContainer does not own this pointer.
......@@ -112,7 +99,7 @@ PyObject* Extend(RepeatedScalarContainer* self, PyObject* value);
// Set the owner field of self and any children of self.
void SetOwner(RepeatedScalarContainer* self,
const shared_ptr<Message>& new_owner);
const CMessage::OwnerRef& new_owner);
} // namespace repeated_scalar_container
} // namespace python
......
......@@ -141,9 +141,11 @@ def MessageToString(message,
as_one_line: Don't introduce newlines between fields.
pointy_brackets: If True, use angle brackets instead of curly braces for
nesting.
use_index_order: If True, print fields of a proto message using the order
defined in source code instead of the field number. By default, use the
field number order.
use_index_order: If True, fields of a proto message will be printed using
the order defined in source code instead of the field number, extensions
will be printed at the end of the message and their relative order is
determined by the extension number. By default, use the field number
order.
float_format: If set, use this to specify floating point number formatting
(per the "Format Specification Mini-Language"); otherwise, str() is used.
use_field_number: If True, print field numbers instead of names.
......@@ -336,11 +338,12 @@ class _Printer(object):
return
fields = message.ListFields()
if self.use_index_order:
fields.sort(key=lambda x: x[0].index)
fields.sort(
key=lambda x: x[0].number if x[0].is_extension else x[0].index)
for field, value in fields:
if _IsMapEntry(field):
for key in sorted(value):
# This is slow for maps with submessage entires because it copies the
# This is slow for maps with submessage entries because it copies the
# entire tree. Unfortunately this would take significant refactoring
# of this file to work around.
#
......@@ -645,6 +648,30 @@ class _Parser(object):
ParseError: In case of text parsing problems.
"""
message_descriptor = message.DESCRIPTOR
if (message_descriptor.full_name == _ANY_FULL_TYPE_NAME and
tokenizer.TryConsume('[')):
type_url_prefix, packed_type_name = self._ConsumeAnyTypeUrl(tokenizer)
tokenizer.Consume(']')
tokenizer.TryConsume(':')
if tokenizer.TryConsume('<'):
expanded_any_end_token = '>'
else:
tokenizer.Consume('{')
expanded_any_end_token = '}'
expanded_any_sub_message = _BuildMessageFromTypeName(packed_type_name,
self.descriptor_pool)
if not expanded_any_sub_message:
raise ParseError('Type %s not found in descriptor pool' %
packed_type_name)
while not tokenizer.TryConsume(expanded_any_end_token):
if tokenizer.AtEnd():
raise tokenizer.ParseErrorPreviousToken('Expected "%s".' %
(expanded_any_end_token,))
self._MergeField(tokenizer, expanded_any_sub_message)
message.Pack(expanded_any_sub_message,
type_url_prefix=type_url_prefix)
return
if tokenizer.TryConsume('['):
name = [tokenizer.ConsumeIdentifier()]
while tokenizer.TryConsume('.'):
......@@ -725,11 +752,12 @@ class _Parser(object):
if (field.label == descriptor.FieldDescriptor.LABEL_REPEATED and
tokenizer.TryConsume('[')):
# Short repeated format, e.g. "foo: [1, 2, 3]"
while True:
merger(tokenizer, message, field)
if tokenizer.TryConsume(']'):
break
tokenizer.Consume(',')
if not tokenizer.TryConsume(']'):
while True:
merger(tokenizer, message, field)
if tokenizer.TryConsume(']'):
break
tokenizer.Consume(',')
else:
merger(tokenizer, message, field)
......@@ -777,33 +805,7 @@ class _Parser(object):
tokenizer.Consume('{')
end_token = '}'
if (field.message_type.full_name == _ANY_FULL_TYPE_NAME and
tokenizer.TryConsume('[')):
type_url_prefix, packed_type_name = self._ConsumeAnyTypeUrl(tokenizer)
tokenizer.Consume(']')
tokenizer.TryConsume(':')
if tokenizer.TryConsume('<'):
expanded_any_end_token = '>'
else:
tokenizer.Consume('{')
expanded_any_end_token = '}'
expanded_any_sub_message = _BuildMessageFromTypeName(packed_type_name,
self.descriptor_pool)
if not expanded_any_sub_message:
raise ParseError('Type %s not found in descriptor pool' %
packed_type_name)
while not tokenizer.TryConsume(expanded_any_end_token):
if tokenizer.AtEnd():
raise tokenizer.ParseErrorPreviousToken('Expected "%s".' %
(expanded_any_end_token,))
self._MergeField(tokenizer, expanded_any_sub_message)
if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
any_message = getattr(message, field.name).add()
else:
any_message = getattr(message, field.name)
any_message.Pack(expanded_any_sub_message,
type_url_prefix=type_url_prefix)
elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
if field.is_extension:
sub_message = message.Extensions[field].add()
elif is_map_entry:
......@@ -812,8 +814,20 @@ class _Parser(object):
sub_message = getattr(message, field.name).add()
else:
if field.is_extension:
if (not self._allow_multiple_scalars and
message.HasExtension(field)):
raise tokenizer.ParseErrorPreviousToken(
'Message type "%s" should not have multiple "%s" extensions.' %
(message.DESCRIPTOR.full_name, field.full_name))
sub_message = message.Extensions[field]
else:
# Also apply _allow_multiple_scalars to message field.
# TODO(jieluo): Change to _allow_singular_overwrites.
if (not self._allow_multiple_scalars and
message.HasField(field.name)):
raise tokenizer.ParseErrorPreviousToken(
'Message type "%s" should not have multiple "%s" fields.' %
(message.DESCRIPTOR.full_name, field.name))
sub_message = getattr(message, field.name)
sub_message.SetInParent()
......
......@@ -64,20 +64,6 @@ MAINTAINERCLEANFILES = \
Makefile.in
nobase_include_HEADERS = \
google/protobuf/stubs/atomic_sequence_num.h \
google/protobuf/stubs/atomicops.h \
google/protobuf/stubs/atomicops_internals_power.h \
google/protobuf/stubs/atomicops_internals_ppc_gcc.h \
google/protobuf/stubs/atomicops_internals_arm64_gcc.h \
google/protobuf/stubs/atomicops_internals_arm_gcc.h \
google/protobuf/stubs/atomicops_internals_arm_qnx.h \
google/protobuf/stubs/atomicops_internals_generic_c11_atomic.h \
google/protobuf/stubs/atomicops_internals_generic_gcc.h \
google/protobuf/stubs/atomicops_internals_mips_gcc.h \
google/protobuf/stubs/atomicops_internals_solaris.h \
google/protobuf/stubs/atomicops_internals_tsan.h \
google/protobuf/stubs/atomicops_internals_x86_gcc.h \
google/protobuf/stubs/atomicops_internals_x86_msvc.h \
google/protobuf/stubs/callback.h \
google/protobuf/stubs/bytestream.h \
google/protobuf/stubs/casts.h \
......@@ -90,8 +76,6 @@ nobase_include_HEADERS = \
google/protobuf/stubs/once.h \
google/protobuf/stubs/platform_macros.h \
google/protobuf/stubs/port.h \
google/protobuf/stubs/scoped_ptr.h \
google/protobuf/stubs/shared_ptr.h \
google/protobuf/stubs/singleton.h \
google/protobuf/stubs/status.h \
google/protobuf/stubs/stl_util.h \
......@@ -189,8 +173,6 @@ libprotobuf_lite_la_LDFLAGS += -Wl,--version-script=$(srcdir)/libprotobuf-lite.m
EXTRA_libprotobuf_lite_la_DEPENDENCIES = libprotobuf-lite.map
endif
libprotobuf_lite_la_SOURCES = \
google/protobuf/stubs/atomicops_internals_x86_gcc.cc \
google/protobuf/stubs/atomicops_internals_x86_msvc.cc \
google/protobuf/stubs/bytestream.cc \
google/protobuf/stubs/bytestream.h \
google/protobuf/stubs/common.cc \
......@@ -201,8 +183,6 @@ libprotobuf_lite_la_SOURCES = \
google/protobuf/stubs/io_win32.h \
google/protobuf/stubs/map_util.h \
google/protobuf/stubs/mathutil.h \
google/protobuf/stubs/once.cc \
google/protobuf/stubs/shared_ptr.h \
google/protobuf/stubs/status.cc \
google/protobuf/stubs/status.h \
google/protobuf/stubs/status_macros.h \
......@@ -772,7 +752,6 @@ protobuf_test_SOURCES = \
google/protobuf/stubs/common_unittest.cc \
google/protobuf/stubs/int128_unittest.cc \
google/protobuf/stubs/io_win32_unittest.cc \
google/protobuf/stubs/once_unittest.cc \
google/protobuf/stubs/statusor_test.cc \
google/protobuf/stubs/status_test.cc \
google/protobuf/stubs/stringpiece_unittest.cc \
......@@ -796,8 +775,8 @@ protobuf_test_SOURCES = \
google/protobuf/message_unittest.cc \
google/protobuf/no_field_presence_test.cc \
google/protobuf/preserve_unknown_enum_test.cc \
google/protobuf/proto3_arena_unittest.cc \
google/protobuf/proto3_arena_lite_unittest.cc \
google/protobuf/proto3_arena_unittest.cc \
google/protobuf/proto3_lite_unittest.cc \
google/protobuf/reflection_ops_unittest.cc \
google/protobuf/repeated_field_reflection_unittest.cc \
......@@ -928,9 +907,7 @@ endif
no_warning_test.cc:
echo "// Generated from Makefile.am" > no_warning_test.cc
for FILE in $(nobase_include_HEADERS); do \
if ! echo $${FILE} | grep "atomicops"; then \
echo "#include <$${FILE}>" >> no_warning_test.cc; \
fi \
echo "#include <$${FILE}>" >> no_warning_test.cc; \
done
echo "int main(int, char**) { return 0; }" >> no_warning_test.cc
......
......@@ -32,6 +32,7 @@
#include <google/protobuf/generated_message_util.h>
namespace google {
namespace protobuf {
namespace internal {
......@@ -84,15 +85,23 @@ bool AnyMetadata::InternalIs(const Descriptor* descriptor) const {
return full_name == descriptor->full_name();
}
bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) {
bool ParseAnyTypeUrl(const string& type_url, string* url_prefix,
string* full_type_name) {
size_t pos = type_url.find_last_of("/");
if (pos == string::npos || pos + 1 == type_url.size()) {
return false;
}
if (url_prefix) {
*url_prefix = type_url.substr(0, pos + 1);
}
*full_type_name = type_url.substr(pos + 1);
return true;
}
bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) {
return ParseAnyTypeUrl(type_url, NULL, full_type_name);
}
bool GetAnyFieldDescriptors(const Message& message,
const FieldDescriptor** type_url_field,
......
......@@ -92,8 +92,19 @@ extern const char kTypeGoogleProdComPrefix[]; // "type.googleprod.com/".
// "type.googleapis.com/rpc.QueryOrigin" will return "rpc.QueryOrigin" in
// *full_type_name. Returns false if the type_url does not have a "/"
// in the type url separating the full type name.
//
// NOTE: this function is available publicly as:
// google::protobuf::Any() // static method on the generated message type.
bool ParseAnyTypeUrl(const string& type_url, string* full_type_name);
// Get the proto type name and prefix from Any::type_url value. For example,
// passing "type.googleapis.com/rpc.QueryOrigin" will return
// "type.googleapis.com/" in *url_prefix and "rpc.QueryOrigin" in
// *full_type_name. Returns false if the type_url does not have a "/" in the
// type url separating the full type name.
bool ParseAnyTypeUrl(const string& type_url, string* url_prefix,
string* full_type_name);
// See if message is of type google.protobuf.Any, if so, return the descriptors
// for "type_url" and "value" fields.
bool GetAnyFieldDescriptors(const Message& message,
......
......@@ -7,7 +7,6 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.h>
......@@ -19,6 +18,7 @@
#include "third_party/protobuf/version.h"
#endif
// @@protoc_insertion_point(includes)
namespace google {
namespace protobuf {
class AnyDefaultTypeInternal {
......@@ -29,14 +29,9 @@ class AnyDefaultTypeInternal {
} // namespace protobuf
} // namespace google
namespace protobuf_google_2fprotobuf_2fany_2eproto {
void InitDefaultsAnyImpl() {
static void InitDefaultsAny() {
GOOGLE_PROTOBUF_VERIFY_VERSION;
#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
::google::protobuf::internal::InitProtobufDefaultsForceUnique();
#else
::google::protobuf::internal::InitProtobufDefaults();
#endif // GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
{
void* ptr = &::google::protobuf::_Any_default_instance_;
new (ptr) ::google::protobuf::Any();
......@@ -45,9 +40,11 @@ void InitDefaultsAnyImpl() {
::google::protobuf::Any::InitAsDefaultInstance();
}
void InitDefaultsAny() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &InitDefaultsAnyImpl);
LIBPROTOBUF_EXPORT ::google::protobuf::internal::SCCInfo<0> scc_info_Any =
{{ATOMIC_VAR_INIT(::google::protobuf::internal::SCCInfoBase::kUninitialized), 0, InitDefaultsAny}, {}};
void InitDefaults() {
::google::protobuf::internal::InitSCC(&scc_info_Any.base);
}
::google::protobuf::Metadata file_level_metadata[1];
......@@ -71,15 +68,14 @@ static ::google::protobuf::Message const * const file_default_instances[] = {
void protobuf_AssignDescriptors() {
AddDescriptors();
::google::protobuf::MessageFactory* factory = NULL;
AssignDescriptors(
"google/protobuf/any.proto", schemas, file_default_instances, TableStruct::offsets, factory,
"google/protobuf/any.proto", schemas, file_default_instances, TableStruct::offsets,
file_level_metadata, NULL, NULL);
}
void protobuf_AssignDescriptorsOnce() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors);
static ::google::protobuf::internal::once_flag once;
::google::protobuf::internal::call_once(once, protobuf_AssignDescriptors);
}
void protobuf_RegisterTypes(const ::std::string&) GOOGLE_PROTOBUF_ATTRIBUTE_COLD;
......@@ -105,8 +101,8 @@ void AddDescriptorsImpl() {
}
void AddDescriptors() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);
static ::google::protobuf::internal::once_flag once;
::google::protobuf::internal::call_once(once, AddDescriptorsImpl);
}
// Force AddDescriptors() to be called at dynamic initialization time.
struct StaticDescriptorInitializer {
......@@ -134,6 +130,11 @@ void Any::PackFrom(const ::google::protobuf::Message& message,
bool Any::UnpackTo(::google::protobuf::Message* message) const {
return _any_metadata_.UnpackTo(message);
}
bool Any::ParseAnyTypeUrl(const string& type_url,
string* full_type_name) {
return ::google::protobuf::internal::ParseAnyTypeUrl(type_url,
full_type_name);
}
#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Any::kTypeUrlFieldNumber;
......@@ -142,16 +143,14 @@ const int Any::kValueFieldNumber;
Any::Any()
: ::google::protobuf::Message(), _internal_metadata_(NULL), _any_metadata_(&type_url_, &value_) {
if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
::protobuf_google_2fprotobuf_2fany_2eproto::InitDefaultsAny();
}
::google::protobuf::internal::InitSCC(
&protobuf_google_2fprotobuf_2fany_2eproto::scc_info_Any.base);
SharedCtor();
// @@protoc_insertion_point(constructor:google.protobuf.Any)
}
Any::Any(const Any& from)
: ::google::protobuf::Message(),
_internal_metadata_(NULL),
_cached_size_(0),
_any_metadata_(&type_url_, &value_) {
_internal_metadata_.MergeFrom(from._internal_metadata_);
type_url_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
......@@ -168,7 +167,6 @@ Any::Any(const Any& from)
void Any::SharedCtor() {
type_url_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
_cached_size_ = 0;
}
Any::~Any() {
......@@ -182,9 +180,7 @@ void Any::SharedDtor() {
}
void Any::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
_cached_size_.Set(size);
}
const ::google::protobuf::Descriptor* Any::descriptor() {
::protobuf_google_2fprotobuf_2fany_2eproto::protobuf_AssignDescriptorsOnce();
......@@ -192,7 +188,7 @@ const ::google::protobuf::Descriptor* Any::descriptor() {
}
const Any& Any::default_instance() {
::protobuf_google_2fprotobuf_2fany_2eproto::InitDefaultsAny();
::google::protobuf::internal::InitSCC(&protobuf_google_2fprotobuf_2fany_2eproto::scc_info_Any.base);
return *internal_default_instance();
}
......@@ -214,7 +210,7 @@ bool Any::MergePartialFromCodedStream(
::google::protobuf::uint32 tag;
// @@protoc_insertion_point(parse_start:google.protobuf.Any)
for (;;) {
::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
::std::pair<::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
tag = p.first;
if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
......@@ -352,9 +348,7 @@ size_t Any::ByteSizeLong() const {
}
int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = cached_size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
SetCachedSize(cached_size);
return total_size;
}
......@@ -414,10 +408,11 @@ void Any::Swap(Any* other) {
}
void Any::InternalSwap(Any* other) {
using std::swap;
type_url_.Swap(&other->type_url_);
value_.Swap(&other->value_);
type_url_.Swap(&other->type_url_, &::google::protobuf::internal::GetEmptyStringAlreadyInited(),
GetArenaNoVirtual());
value_.Swap(&other->value_, &::google::protobuf::internal::GetEmptyStringAlreadyInited(),
GetArenaNoVirtual());
_internal_metadata_.Swap(&other->_internal_metadata_);
swap(_cached_size_, other->_cached_size_);
}
::google::protobuf::Metadata Any::GetMetadata() const {
......@@ -431,7 +426,7 @@ void Any::InternalSwap(Any* other) {
} // namespace google
namespace google {
namespace protobuf {
template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::google::protobuf::Any* Arena::Create< ::google::protobuf::Any >(Arena* arena) {
template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::google::protobuf::Any* Arena::CreateMaybeMessage< ::google::protobuf::Any >(Arena* arena) {
return Arena::CreateInternal< ::google::protobuf::Any >(arena);
}
} // namespace protobuf
......
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/protobuf/any.proto
#ifndef PROTOBUF_google_2fprotobuf_2fany_2eproto_INCLUDED
#define PROTOBUF_google_2fprotobuf_2fany_2eproto_INCLUDED
#ifndef PROTOBUF_INCLUDED_google_2fprotobuf_2fany_2eproto
#define PROTOBUF_INCLUDED_google_2fprotobuf_2fany_2eproto
#include <string>
......@@ -24,6 +24,7 @@
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/inlined_string_field.h>
#include <google/protobuf/metadata.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h> // IWYU pragma: export
......@@ -31,6 +32,7 @@
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/any.h>
// @@protoc_insertion_point(includes)
#define PROTOBUF_INTERNAL_EXPORT_protobuf_google_2fprotobuf_2fany_2eproto LIBPROTOBUF_EXPORT
namespace protobuf_google_2fprotobuf_2fany_2eproto {
// Internal implementation detail -- do not use these members.
......@@ -43,11 +45,6 @@ struct LIBPROTOBUF_EXPORT TableStruct {
static const ::google::protobuf::uint32 offsets[];
};
void LIBPROTOBUF_EXPORT AddDescriptors();
void LIBPROTOBUF_EXPORT InitDefaultsAnyImpl();
void LIBPROTOBUF_EXPORT InitDefaultsAny();
inline void LIBPROTOBUF_EXPORT InitDefaults() {
InitDefaultsAny();
}
} // namespace protobuf_google_2fprotobuf_2fany_2eproto
namespace google {
namespace protobuf {
......@@ -58,7 +55,7 @@ LIBPROTOBUF_EXPORT extern AnyDefaultTypeInternal _Any_default_instance_;
} // namespace google
namespace google {
namespace protobuf {
template<> LIBPROTOBUF_EXPORT ::google::protobuf::Any* Arena::Create< ::google::protobuf::Any>(Arena*);
template<> LIBPROTOBUF_EXPORT ::google::protobuf::Any* Arena::CreateMaybeMessage<::google::protobuf::Any>(Arena*);
} // namespace protobuf
} // namespace google
namespace google {
......@@ -100,7 +97,7 @@ class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message /* @@protoc_in
return reinterpret_cast<const Any*>(
&_Any_default_instance_);
}
static PROTOBUF_CONSTEXPR int const kIndexInFileMessages =
static constexpr int kIndexInFileMessages =
0;
// implements Any -----------------------------------------------
......@@ -112,6 +109,8 @@ class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message /* @@protoc_in
template<typename T> bool Is() const {
return _any_metadata_.Is<T>();
}
static bool ParseAnyTypeUrl(const string& type_url,
string* full_type_name);
void Swap(Any* other);
friend void swap(Any& a, Any& b) {
......@@ -120,32 +119,33 @@ class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message /* @@protoc_in
// implements Message ----------------------------------------------
inline Any* New() const PROTOBUF_FINAL {
return ::google::protobuf::Arena::Create<Any>(NULL);
inline Any* New() const final {
return CreateMaybeMessage<Any>(NULL);
}
Any* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL {
return ::google::protobuf::Arena::Create<Any>(arena);
Any* New(::google::protobuf::Arena* arena) const final {
return CreateMaybeMessage<Any>(arena);
}
void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
void CopyFrom(const ::google::protobuf::Message& from) final;
void MergeFrom(const ::google::protobuf::Message& from) final;
void CopyFrom(const Any& from);
void MergeFrom(const Any& from);
void Clear() PROTOBUF_FINAL;
bool IsInitialized() const PROTOBUF_FINAL;
void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const PROTOBUF_FINAL;
size_t ByteSizeLong() const final;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
::google::protobuf::io::CodedInputStream* input) final;
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
::google::protobuf::io::CodedOutputStream* output) const final;
::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
bool deterministic, ::google::protobuf::uint8* target) const final;
int GetCachedSize() const final { return _cached_size_.Get(); }
private:
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const PROTOBUF_FINAL;
void SetCachedSize(int size) const final;
void InternalSwap(Any* other);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
......@@ -156,7 +156,7 @@ class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message /* @@protoc_in
}
public:
::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
::google::protobuf::Metadata GetMetadata() const final;
// nested types ----------------------------------------------------
......@@ -196,10 +196,9 @@ class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message /* @@protoc_in
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
::google::protobuf::internal::ArenaStringPtr type_url_;
::google::protobuf::internal::ArenaStringPtr value_;
mutable int _cached_size_;
mutable ::google::protobuf::internal::CachedSize _cached_size_;
::google::protobuf::internal::AnyMetadata _any_metadata_;
friend struct ::protobuf_google_2fprotobuf_2fany_2eproto::TableStruct;
friend void ::protobuf_google_2fprotobuf_2fany_2eproto::InitDefaultsAnyImpl();
};
// ===================================================================
......@@ -329,4 +328,4 @@ inline void Any::set_allocated_value(::std::string* value) {
// @@protoc_insertion_point(global_scope)
#endif // PROTOBUF_google_2fprotobuf_2fany_2eproto_INCLUDED
#endif // PROTOBUF_INCLUDED_google_2fprotobuf_2fany_2eproto
This diff is collapsed.
This diff is collapsed.
......@@ -48,7 +48,7 @@ namespace protobuf {
namespace internal {
google::protobuf::internal::SequenceNumber ArenaImpl::lifecycle_id_generator_;
std::atomic<int64> ArenaImpl::lifecycle_id_generator_;
#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
ArenaImpl::ThreadCache& ArenaImpl::thread_cache() {
static internal::ThreadLocalStorage<ThreadCache>* thread_cache_ =
......@@ -65,9 +65,10 @@ GOOGLE_THREAD_LOCAL ArenaImpl::ThreadCache ArenaImpl::thread_cache_ = {-1, NULL}
#endif
void ArenaImpl::Init() {
lifecycle_id_ = lifecycle_id_generator_.GetNext();
google::protobuf::internal::NoBarrier_Store(&hint_, 0);
google::protobuf::internal::NoBarrier_Store(&threads_, 0);
lifecycle_id_ =
lifecycle_id_generator_.fetch_add(1, std::memory_order_relaxed);
hint_.store(nullptr, std::memory_order_relaxed);
threads_.store(nullptr, std::memory_order_relaxed);
if (initial_block_) {
// Thread which calls Init() owns the first block. This allows the
......@@ -77,13 +78,12 @@ void ArenaImpl::Init() {
SerialArena* serial =
SerialArena::New(initial_block_, &thread_cache(), this);
serial->set_next(NULL);
google::protobuf::internal::NoBarrier_Store(&threads_,
reinterpret_cast<google::protobuf::internal::AtomicWord>(serial));
google::protobuf::internal::NoBarrier_Store(&space_allocated_,
options_.initial_block_size);
threads_.store(serial, std::memory_order_relaxed);
space_allocated_.store(options_.initial_block_size,
std::memory_order_relaxed);
CacheSerialArena(serial);
} else {
google::protobuf::internal::NoBarrier_Store(&space_allocated_, 0);
space_allocated_.store(0, std::memory_order_relaxed);
}
}
......@@ -118,7 +118,7 @@ ArenaImpl::Block* ArenaImpl::NewBlock(Block* last_block, size_t min_bytes) {
void* mem = options_.block_alloc(size);
Block* b = new (mem) Block(size, last_block);
google::protobuf::internal::NoBarrier_AtomicIncrement(&space_allocated_, size);
space_allocated_.fetch_add(size, std::memory_order_relaxed);
return b;
}
......@@ -142,6 +142,7 @@ void ArenaImpl::SerialArena::AddCleanupFallback(void* elem,
AddCleanup(elem, cleanup);
}
GOOGLE_PROTOBUF_ATTRIBUTE_FUNC_ALIGN(32)
void* ArenaImpl::AllocateAligned(size_t n) {
SerialArena* arena;
if (GOOGLE_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
......@@ -199,8 +200,7 @@ bool ArenaImpl::GetSerialArenaFast(ArenaImpl::SerialArena** arena) {
// Check whether we own the last accessed SerialArena on this arena. This
// fast path optimizes the case where a single thread uses multiple arenas.
SerialArena* serial =
reinterpret_cast<SerialArena*>(google::protobuf::internal::Acquire_Load(&hint_));
SerialArena* serial = hint_.load(std::memory_order_acquire);
if (GOOGLE_PREDICT_TRUE(serial != NULL && serial->owner() == tc)) {
*arena = serial;
return true;
......@@ -235,12 +235,11 @@ void* ArenaImpl::SerialArena::AllocateAlignedFallback(size_t n) {
}
uint64 ArenaImpl::SpaceAllocated() const {
return google::protobuf::internal::NoBarrier_Load(&space_allocated_);
return space_allocated_.load(std::memory_order_relaxed);
}
uint64 ArenaImpl::SpaceUsed() const {
SerialArena* serial =
reinterpret_cast<SerialArena*>(google::protobuf::internal::Acquire_Load(&threads_));
SerialArena* serial = threads_.load(std::memory_order_acquire);
uint64 space_used = 0;
for ( ; serial; serial = serial->next()) {
space_used += serial->SpaceUsed();
......@@ -264,8 +263,7 @@ uint64 ArenaImpl::FreeBlocks() {
uint64 space_allocated = 0;
// By omitting an Acquire barrier we ensure that any user code that doesn't
// properly synchronize Reset() or the destructor will throw a TSAN warning.
SerialArena* serial =
reinterpret_cast<SerialArena*>(google::protobuf::internal::NoBarrier_Load(&threads_));
SerialArena* serial = threads_.load(std::memory_order_relaxed);
while (serial) {
// This is inside a block we are freeing, so we need to read it now.
......@@ -311,8 +309,7 @@ uint64 ArenaImpl::SerialArena::Free(ArenaImpl::SerialArena* serial,
void ArenaImpl::CleanupList() {
// By omitting an Acquire barrier we ensure that any user code that doesn't
// properly synchronize Reset() or the destructor will throw a TSAN warning.
SerialArena* serial =
reinterpret_cast<SerialArena*>(google::protobuf::internal::NoBarrier_Load(&threads_));
SerialArena* serial = threads_.load(std::memory_order_relaxed);
for ( ; serial; serial = serial->next()) {
serial->CleanupList();
......@@ -368,8 +365,7 @@ ArenaImpl::SerialArena* ArenaImpl::SerialArena::New(Block* b, void* owner,
GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
ArenaImpl::SerialArena* ArenaImpl::GetSerialArenaFallback(void* me) {
// Look for this SerialArena in our linked list.
SerialArena* serial =
reinterpret_cast<SerialArena*>(google::protobuf::internal::Acquire_Load(&threads_));
SerialArena* serial = threads_.load(std::memory_order_acquire);
for ( ; serial; serial = serial->next()) {
if (serial->owner() == me) {
break;
......@@ -382,12 +378,11 @@ ArenaImpl::SerialArena* ArenaImpl::GetSerialArenaFallback(void* me) {
Block* b = NewBlock(NULL, kSerialArenaSize);
serial = SerialArena::New(b, me, this);
google::protobuf::internal::AtomicWord head;
SerialArena* head = threads_.load(std::memory_order_relaxed);
do {
head = google::protobuf::internal::NoBarrier_Load(&threads_);
serial->set_next(reinterpret_cast<SerialArena*>(head));
} while (google::protobuf::internal::Release_CompareAndSwap(
&threads_, head, reinterpret_cast<google::protobuf::internal::AtomicWord>(serial)) != head);
serial->set_next(head);
} while (!threads_.compare_exchange_weak(
head, serial, std::memory_order_release, std::memory_order_relaxed));
}
CacheSerialArena(serial);
......
This diff is collapsed.
......@@ -33,13 +33,11 @@
#ifndef GOOGLE_PROTOBUF_ARENA_IMPL_H__
#define GOOGLE_PROTOBUF_ARENA_IMPL_H__
#include <atomic>
#include <limits>
#include <google/protobuf/stubs/atomic_sequence_num.h>
#include <google/protobuf/stubs/atomicops.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/mutex.h>
#include <google/protobuf/stubs/port.h>
......@@ -248,7 +246,7 @@ class LIBPROTOBUF_EXPORT ArenaImpl {
int64 last_lifecycle_id_seen;
SerialArena* last_serial_arena;
};
static google::protobuf::internal::SequenceNumber lifecycle_id_generator_;
static std::atomic<int64> lifecycle_id_generator_;
#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
// Android ndk does not support GOOGLE_THREAD_LOCAL keyword so we use a custom thread
// local storage class we implemented.
......@@ -277,12 +275,15 @@ class LIBPROTOBUF_EXPORT ArenaImpl {
// TODO(haberman): evaluate whether we would gain efficiency by getting rid
// of hint_. It's the only write we do to ArenaImpl in the allocation path,
// which will dirty the cache line.
google::protobuf::internal::Release_Store(&hint_, reinterpret_cast<google::protobuf::internal::AtomicWord>(serial));
hint_.store(serial, std::memory_order_release);
}
google::protobuf::internal::AtomicWord threads_; // Pointer to a linked list of SerialArena.
google::protobuf::internal::AtomicWord hint_; // Fast thread-local block access
google::protobuf::internal::AtomicWord space_allocated_; // Sum of sizes of all allocated blocks.
std::atomic<SerialArena*>
threads_; // Pointer to a linked list of SerialArena.
std::atomic<SerialArena*> hint_; // Fast thread-local block access
std::atomic<size_t> space_allocated_; // Total size of all allocated blocks.
Block *initial_block_; // If non-NULL, points to the block that came from
// user data.
......@@ -297,18 +298,20 @@ class LIBPROTOBUF_EXPORT ArenaImpl {
Options options_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArenaImpl);
// All protos have pointers back to the arena hence Arena must have
// pointer stability.
ArenaImpl(ArenaImpl&&) = delete;
ArenaImpl& operator=(ArenaImpl&&) = delete;
public:
// kBlockHeaderSize is sizeof(Block), aligned up to the nearest multiple of 8
// to protect the invariant that pos is always at a multiple of 8.
static const size_t kBlockHeaderSize = (sizeof(Block) + 7) & -8;
static const size_t kSerialArenaSize = (sizeof(SerialArena) + 7) & -8;
#if LANG_CXX11
static_assert(kBlockHeaderSize % 8 == 0,
"kBlockHeaderSize must be a multiple of 8.");
static_assert(kSerialArenaSize % 8 == 0,
"kSerialArenaSize must be a multiple of 8.");
#endif
};
} // namespace internal
......
......@@ -50,7 +50,7 @@ void TestParseCorruptedString(const T& message) {
s[i] ^= c;
google::protobuf::Arena arena;
T* message =
google::protobuf::Arena::CreateMessage<T>(use_arena ? &arena : NULL);
google::protobuf::Arena::CreateMessage<T>(use_arena ? &arena : nullptr);
if (message->ParseFromString(s)) {
++success_count;
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -35,9 +35,6 @@
#include <algorithm>
#include <cstdlib>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <string>
#include <vector>
......
......@@ -31,9 +31,6 @@
#include <google/protobuf/compiler/annotation_test_util.h>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/compiler/command_line_interface.h>
#include <google/protobuf/io/printer.h>
......
......@@ -179,7 +179,7 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
void EnumGenerator::
GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
printer->Print(
"template <> struct is_proto_enum< $classname$> : ::google::protobuf::internal::true_type "
"template <> struct is_proto_enum< $classname$> : ::std::true_type "
"{};\n",
"classname", ClassName(descriptor_, true));
if (HasDescriptorMethods(descriptor_->file(), options_)) {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment