Merge pull request #9090 from acozzette/sync-stage

Integrate from Piper for C++, Java, and Python
This commit is contained in:
Adam Cozzette 2021-10-12 16:37:01 -07:00 committed by GitHub
commit 3e1967e10b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
86 changed files with 4215 additions and 3178 deletions

1
BUILD
View File

@ -147,6 +147,7 @@ cc_library(
"src/google/protobuf/message_lite.cc",
"src/google/protobuf/parse_context.cc",
"src/google/protobuf/repeated_field.cc",
"src/google/protobuf/repeated_ptr_field.cc",
"src/google/protobuf/stubs/bytestream.cc",
"src/google/protobuf/stubs/common.cc",
"src/google/protobuf/stubs/int128.cc",

View File

@ -1,6 +1,19 @@
Unreleased Changes (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)
Protocol Compiler
Python
* Proto2 DecodeError now includes message name in error message
C++
* Make proto2::Message::DiscardUnknownFields() non-virtual
* Separate RepeatedPtrField into its own header file
* For default floating point values of 0, consider all bits significant
Java
* For default floating point values of 0, consider all bits significant
* Annotate `//java/com/google/protobuf/util/...` with nullness annotations
Kotlin
* Switch Kotlin proto DSLs to be implemented with inline value classes
2021-10-04 version 3.18.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)

View File

@ -38,13 +38,15 @@ bind(
load("@rules_jvm_external//:defs.bzl", "maven_install")
maven_install(
artifacts = [
"com.google.code.findbugs:jsr305:3.0.2",
"com.google.code.gson:gson:2.8.6",
"com.google.errorprone:error_prone_annotations:2.3.2",
"com.google.j2objc:j2obj_annotations:1.3",
"com.google.j2objc:j2objc-annotations:1.3",
"com.google.guava:guava:30.1.1-jre",
"com.google.truth:truth:1.1.2",
"junit:junit:4.12",
"org.easymock:easymock:3.2",
],
repositories = [
"https://repo1.maven.org/maven2",
@ -78,6 +80,11 @@ bind(
actual = "@maven//:com_google_j2objc_j2objc_annotations",
)
bind(
name = "jsr305",
actual = "@maven//:com_google_code_findbugs_jsr305",
)
bind(
name = "junit",
actual = "@maven//:junit_junit",
@ -88,11 +95,6 @@ bind(
actual = "@maven//:org_easymock_easymock",
)
bind(
name = "easymock_classextension",
actual = "@maven//:org_easymock_easymockclassextension",
)
bind(
name = "truth",
actual = "@maven//:com_google_truth_truth",

View File

@ -93,6 +93,7 @@ copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\port_undef.inc" inclu
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection.h" include\google\protobuf\reflection.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection_ops.h" include\google\protobuf\reflection_ops.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_field.h" include\google\protobuf\repeated_field.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_ptr_field.h" include\google\protobuf\repeated_ptr_field.h
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

View File

@ -19,6 +19,7 @@ set(libprotobuf_lite_files
${protobuf_source_dir}/src/google/protobuf/message_lite.cc
${protobuf_source_dir}/src/google/protobuf/parse_context.cc
${protobuf_source_dir}/src/google/protobuf/repeated_field.cc
${protobuf_source_dir}/src/google/protobuf/repeated_ptr_field.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
@ -65,6 +66,7 @@ set(libprotobuf_lite_includes
${protobuf_source_dir}/src/google/protobuf/parse_context.h
${protobuf_source_dir}/src/google/protobuf/port.h
${protobuf_source_dir}/src/google/protobuf/repeated_field.h
${protobuf_source_dir}/src/google/protobuf/repeated_ptr_field.h
${protobuf_source_dir}/src/google/protobuf/stubs/bytestream.h
${protobuf_source_dir}/src/google/protobuf/stubs/callback.h
${protobuf_source_dir}/src/google/protobuf/stubs/casts.h

View File

@ -255,7 +255,6 @@ junit_tests(
":java_test_protos_java_proto",
":test_util",
"//external:easymock",
"//external:easymock_classextension",
"//external:guava",
"//external:junit",
"//external:truth",

View File

@ -49,6 +49,7 @@ import com.google.protobuf.DescriptorProtos.OneofOptions;
import com.google.protobuf.DescriptorProtos.ServiceDescriptorProto;
import com.google.protobuf.DescriptorProtos.ServiceOptions;
import com.google.protobuf.Descriptors.FileDescriptor.Syntax;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
@ -59,7 +60,6 @@ import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.logging.Logger;
/**
@ -1816,6 +1816,15 @@ public final class Descriptors {
valuesSortedByNumber, distinctNumbers, EnumValueDescriptor.NUMBER_GETTER, number);
}
private static class UnknownEnumValueReference extends WeakReference<EnumValueDescriptor> {
private final int number;
private UnknownEnumValueReference(int number, EnumValueDescriptor descriptor) {
super(descriptor);
this.number = number;
}
}
/**
* Get the enum value for a number. If no enum value has this number, construct an
* EnumValueDescriptor for it.
@ -1827,43 +1836,28 @@ public final class Descriptors {
}
// The number represents an unknown enum value.
synchronized (this) {
// Descriptors are compared by object identity so for the same number
// we need to return the same EnumValueDescriptor object. This means
// we have to store created EnumValueDescriptors. However, as there
// are potentially 2G unknown enum values, storing all of these
// objects persistently will consume lots of memory for long-running
// services and it's also unnecessary as not many EnumValueDescriptors
// will be used at the same time.
//
// To solve the problem we take advantage of Java's weak references and
// rely on gc to release unused descriptors.
//
// Here is how it works:
// * We store unknown EnumValueDescriptors in a WeakHashMap with the
// value being a weak reference to the descriptor.
// * The descriptor holds a strong reference to the key so as long
// as the EnumValueDescriptor is in use, the key will be there
// and the corresponding map entry will be there. Following-up
// queries with the same number will return the same descriptor.
// * If the user no longer uses an unknown EnumValueDescriptor,
// it will be gc-ed since we only hold a weak reference to it in
// the map. The key in the corresponding map entry will also be
// gc-ed as the only strong reference to it is in the descriptor
// which is just gc-ed. With the key being gone WeakHashMap will
// then remove the whole entry. This way unknown descriptors will
// be freed automatically and we don't need to do anything to
// clean-up unused map entries.
// Note: We must use "new Integer(number)" here because we don't want
// these Integer objects to be cached.
Integer key = new Integer(number);
WeakReference<EnumValueDescriptor> reference = unknownValues.get(key);
if (reference != null) {
result = reference.get();
if (cleanupQueue == null) {
cleanupQueue = new ReferenceQueue<EnumValueDescriptor>();
unknownValues = new HashMap<Integer, WeakReference<EnumValueDescriptor>>();
} else {
while (true) {
UnknownEnumValueReference toClean = (UnknownEnumValueReference) cleanupQueue.poll();
if (toClean == null) {
break;
}
unknownValues.remove(toClean.number);
}
}
// There are two ways we can be missing a value: it wasn't in the map, or the reference
// has been GC'd. (It may even have been GC'd since we cleaned up the references a few
// lines of code ago.) So get out the reference, if it's still present...
WeakReference<EnumValueDescriptor> reference = unknownValues.get(number);
result = (reference == null) ? null : reference.get();
if (result == null) {
result = new EnumValueDescriptor(this, key);
unknownValues.put(key, new WeakReference<EnumValueDescriptor>(result));
result = new EnumValueDescriptor(this, number);
unknownValues.put(number, new UnknownEnumValueReference(number, result));
}
}
return result;
@ -1882,8 +1876,8 @@ public final class Descriptors {
private final EnumValueDescriptor[] values;
private final EnumValueDescriptor[] valuesSortedByNumber;
private final int distinctNumbers;
private final WeakHashMap<Integer, WeakReference<EnumValueDescriptor>> unknownValues =
new WeakHashMap<>();
private Map<Integer, WeakReference<EnumValueDescriptor>> unknownValues = null;
private ReferenceQueue<EnumValueDescriptor> cleanupQueue = null;
private EnumDescriptor(
final EnumDescriptorProto proto,

View File

@ -54,6 +54,7 @@ public final class Internal {
private Internal() {}
static final Charset US_ASCII = Charset.forName("US-ASCII");
static final Charset UTF_8 = Charset.forName("UTF-8");
static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");

View File

@ -134,7 +134,7 @@ public class InvalidProtocolBufferException extends IOException {
return new InvalidWireTypeException("Protocol message tag had invalid wire type.");
}
/** Exception indicating that and unexpected wire type was encountered for a field. */
/** Exception indicating that an unexpected wire type was encountered for a field. */
@ExperimentalApi
public static class InvalidWireTypeException extends InvalidProtocolBufferException {
private static final long serialVersionUID = 3283890091615336259L;

View File

@ -187,10 +187,10 @@ final class MessageLiteToString {
return ((Integer) o) == 0;
}
if (o instanceof Float) {
return ((Float) o) == 0f;
return Float.floatToRawIntBits((Float) o) == 0;
}
if (o instanceof Double) {
return ((Double) o) == 0d;
return Double.doubleToRawLongBits((Double) o) == 0;
}
if (o instanceof String) {
return o.equals("");

View File

@ -5808,9 +5808,9 @@ final class MessageSchema<T> implements Schema<T> {
final long offset = offset(typeAndOffset);
switch (type(typeAndOffset)) {
case 0: // DOUBLE:
return UnsafeUtil.getDouble(message, offset) != 0D;
return Double.doubleToRawLongBits(UnsafeUtil.getDouble(message, offset)) != 0L;
case 1: // FLOAT:
return UnsafeUtil.getFloat(message, offset) != 0F;
return Float.floatToRawIntBits(UnsafeUtil.getFloat(message, offset)) != 0;
case 2: // INT64:
return UnsafeUtil.getLong(message, offset) != 0L;
case 3: // UINT64:

View File

@ -68,13 +68,13 @@ final class SchemaUtil {
}
public static void writeDouble(int fieldNumber, double value, Writer writer) throws IOException {
if (Double.compare(value, 0.0) != 0) {
if (Double.doubleToRawLongBits(value) != 0) {
writer.writeDouble(fieldNumber, value);
}
}
public static void writeFloat(int fieldNumber, float value, Writer writer) throws IOException {
if (Float.compare(value, 0.0f) != 0) {
if (Float.floatToRawIntBits(value) != 0) {
writer.writeFloat(fieldNumber, value);
}
}

View File

@ -90,7 +90,7 @@ public class TextFormatParseInfoTree {
/**
* Retrieve all the locations of a field.
*
* @param fieldDescriptor the @{link FieldDescriptor} of the desired field
* @param fieldDescriptor the {@link FieldDescriptor} of the desired field
* @return a list of the locations of values of the field. If there are not values or the field
* doesn't exist, an empty list is returned.
*/
@ -105,7 +105,7 @@ public class TextFormatParseInfoTree {
* <p>Returns the {@link TextFormatParseLocation} for index-th value of the field in the parsed
* text.
*
* @param fieldDescriptor the @{link FieldDescriptor} of the desired field
* @param fieldDescriptor the {@link FieldDescriptor} of the desired field
* @param index the index of the value.
* @return the {@link TextFormatParseLocation} of the value
* @throws IllegalArgumentException index is out of range
@ -117,7 +117,7 @@ public class TextFormatParseInfoTree {
/**
* Retrieve a list of all the location information trees for a sub message field.
*
* @param fieldDescriptor the @{link FieldDescriptor} of the desired field
* @param fieldDescriptor the {@link FieldDescriptor} of the desired field
* @return A list of {@link TextFormatParseInfoTree}
*/
public List<TextFormatParseInfoTree> getNestedTrees(final FieldDescriptor fieldDescriptor) {
@ -128,7 +128,7 @@ public class TextFormatParseInfoTree {
/**
* Returns the parse info tree for the given field, which must be a message type.
*
* @param fieldDescriptor the @{link FieldDescriptor} of the desired sub message
* @param fieldDescriptor the {@link FieldDescriptor} of the desired sub message
* @param index the index of message value.
* @return the {@code ParseInfoTree} of the message value. {@code null} is returned if the field
* doesn't exist or the index is out of range.

View File

@ -1371,29 +1371,39 @@ final class Utf8 {
String.format("buffer length=%d, index=%d, size=%d", bytes.length, index, size));
}
int offset = index;
final int limit = offset + size;
int offset = index + unsafeEstimateConsecutiveAscii(bytes, index, size);
final int limit = index + size;
// The longest possible resulting String is the same as the number of input bytes, when it is
// all ASCII. For other cases, this over-allocates and we will truncate in the end.
char[] resultArr = new char[size];
int resultPos = 0;
// Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this).
// This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
// get an "exact" consecutive ASCII
while (offset < limit) {
byte b = UnsafeUtil.getByte(bytes, offset);
if (!DecodeUtil.isOneByte(b)) {
if (b < 0) {
break;
}
offset++;
DecodeUtil.handleOneByte(b, resultArr, resultPos++);
}
if (offset == limit) {
// The entire byte sequence is ASCII. Don't bother copying to a char[], JVMs using
// compact strings will just turn it back into the same byte[].
return new String(bytes, index, size, Internal.US_ASCII);
}
// It's not all ASCII, at this point. This may over-allocate, but we will truncate in the
// end.
char[] resultArr = new char[size];
int resultPos = 0;
// Copy over the initial run of ASCII.
for (int i = index; i < offset; i++) {
DecodeUtil.handleOneByte(UnsafeUtil.getByte(bytes, i), resultArr, resultPos++);
}
while (offset < limit) {
byte byte1 = UnsafeUtil.getByte(bytes, offset++);
if (DecodeUtil.isOneByte(byte1)) {
DecodeUtil.handleOneByte(byte1, resultArr, resultPos++);
// It's common for there to be multiple ASCII characters in a run mixed in, so add an
// extra optimized loop to take care of these runs.
while (offset < limit) {
@ -1656,7 +1666,17 @@ final class Utf8 {
return 0;
}
for (int i = 0; i < maxChars; i++) {
int i;
for (i = 0; i + 8 <= maxChars; i += 8) {
if ((UnsafeUtil.getLong(bytes, UnsafeUtil.BYTE_ARRAY_BASE_OFFSET + offset)
& ASCII_MASK_LONG)
!= 0L) {
break;
}
offset += 8;
}
for (; i < maxChars; i++) {
if (UnsafeUtil.getByte(bytes, offset++) < 0) {
return i;
}

View File

@ -49,7 +49,7 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class CheckUtf8Test {
private static final String UTF8_BYTE_STRING_TEXT = "some text";
private static final String UTF8_BYTE_STRING_TEXT = "some text π \uD83D\uDE00";
private static final ByteString UTF8_BYTE_STRING = ByteString.copyFromUtf8(UTF8_BYTE_STRING_TEXT);
private static final ByteString NON_UTF8_BYTE_STRING =
ByteString.copyFrom(new byte[] {(byte) 0x80}); // A lone continuation byte.

View File

@ -1,3 +1,33 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.Utf8.Processor;
@ -28,12 +58,13 @@ public class DecodeUtf8Test extends TestCase {
public void testOneByte() throws Exception {
int valid = 0;
ByteBuffer buffer = ByteBuffer.allocateDirect(1);
for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
ByteString bs = ByteString.copyFrom(new byte[] { (byte) i });
if (!bs.isValidUtf8()) {
assertInvalid(bs.toByteArray());
} else {
ByteString bs = ByteString.copyFrom(new byte[] {(byte) i});
if (bs.isValidUtf8()) {
valid++;
} else {
assertInvalid(bs.toByteArray(), buffer);
}
}
assertEquals(IsValidUtf8TestUtil.EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, valid);
@ -41,13 +72,14 @@ public class DecodeUtf8Test extends TestCase {
public void testTwoBytes() throws Exception {
int valid = 0;
ByteBuffer buffer = ByteBuffer.allocateDirect(2);
for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
for (int j = Byte.MIN_VALUE; j <= Byte.MAX_VALUE; j++) {
ByteString bs = ByteString.copyFrom(new byte[]{(byte) i, (byte) j});
if (!bs.isValidUtf8()) {
assertInvalid(bs.toByteArray());
} else {
ByteString bs = ByteString.copyFrom(new byte[] {(byte) i, (byte) j});
if (bs.isValidUtf8()) {
valid++;
} else {
assertInvalid(bs.toByteArray(), buffer);
}
}
}
@ -55,34 +87,30 @@ public class DecodeUtf8Test extends TestCase {
}
public void testThreeBytes() throws Exception {
// Travis' OOM killer doesn't like this test
if (System.getenv("TRAVIS") == null) {
int count = 0;
int valid = 0;
for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
for (int j = Byte.MIN_VALUE; j <= Byte.MAX_VALUE; j++) {
for (int k = Byte.MIN_VALUE; k <= Byte.MAX_VALUE; k++) {
byte[] bytes = new byte[]{(byte) i, (byte) j, (byte) k};
ByteString bs = ByteString.copyFrom(bytes);
if (!bs.isValidUtf8()) {
assertInvalid(bytes);
} else {
valid++;
}
count++;
if (count % 1000000L == 0) {
logger.info("Processed " + (count / 1000000L) + " million characters");
}
int count = 0;
int valid = 0;
ByteBuffer buffer = ByteBuffer.allocateDirect(3);
for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
for (int j = Byte.MIN_VALUE; j <= Byte.MAX_VALUE; j++) {
for (int k = Byte.MIN_VALUE; k <= Byte.MAX_VALUE; k++) {
byte[] bytes = new byte[] {(byte) i, (byte) j, (byte) k};
ByteString bs = ByteString.copyFrom(bytes);
if (bs.isValidUtf8()) {
valid++;
} else {
assertInvalid(bytes, buffer);
}
count++;
if (count % 1000000L == 0) {
logger.info("Processed " + (count / 1000000L) + " million characters");
}
}
}
assertEquals(IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT, valid);
}
assertEquals(IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT, valid);
}
/**
* Tests that round tripping of a sample of four byte permutations work.
*/
/** Tests that round tripping of a sample of four byte permutations work. */
public void testInvalid_4BytesSamples() throws Exception {
// Bad trailing bytes
assertInvalid(0xF0, 0xA4, 0xAD, 0x7F);
@ -99,8 +127,7 @@ public class DecodeUtf8Test extends TestCase {
// German
assertRoundTrips("Quizdeltagerne spiste jordb\u00e6r med fl\u00f8de, mens cirkusklovnen");
// Japanese
assertRoundTrips(
"\u3044\u308d\u306f\u306b\u307b\u3078\u3068\u3061\u308a\u306c\u308b\u3092");
assertRoundTrips("\u3044\u308d\u306f\u306b\u307b\u3078\u3068\u3061\u308a\u306c\u308b\u3092");
// Hebrew
assertRoundTrips(
"\u05d3\u05d2 \u05e1\u05e7\u05e8\u05df \u05e9\u05d8 \u05d1\u05d9\u05dd "
@ -115,9 +142,10 @@ public class DecodeUtf8Test extends TestCase {
assertRoundTrips(
"\u8fd4\u56de\u94fe\u4e2d\u7684\u4e0b\u4e00\u4e2a\u4ee3\u7406\u9879\u9009\u62e9\u5668");
// Chinese with 4-byte chars
assertRoundTrips("\uD841\uDF0E\uD841\uDF31\uD841\uDF79\uD843\uDC53\uD843\uDC78"
+ "\uD843\uDC96\uD843\uDCCF\uD843\uDCD5\uD843\uDD15\uD843\uDD7C\uD843\uDD7F"
+ "\uD843\uDE0E\uD843\uDE0F\uD843\uDE77\uD843\uDE9D\uD843\uDEA2");
assertRoundTrips(
"\uD841\uDF0E\uD841\uDF31\uD841\uDF79\uD843\uDC53\uD843\uDC78"
+ "\uD843\uDC96\uD843\uDCCF\uD843\uDCD5\uD843\uDD15\uD843\uDD7C\uD843\uDD7F"
+ "\uD843\uDE0E\uD843\uDE0F\uD843\uDE77\uD843\uDE9D\uD843\uDEA2");
// Mixed
assertRoundTrips(
"The quick brown \u3044\u308d\u306f\u306b\u307b\u3078\u8fd4\u56de\u94fe"
@ -132,7 +160,7 @@ public class DecodeUtf8Test extends TestCase {
// Max overlong
assertInvalid(0xc1, 0xbf);
assertInvalid(0xe0, 0x9f, 0xbf);
assertInvalid(0xf0 ,0x8f, 0xbf, 0xbf);
assertInvalid(0xf0, 0x8f, 0xbf, 0xbf);
// null overlong
assertInvalid(0xc0, 0x80);
@ -168,7 +196,7 @@ public class DecodeUtf8Test extends TestCase {
}
public void testInvalidBufferSlice() throws Exception {
byte[] bytes = "The quick brown fox jumps over the lazy dog".getBytes(Internal.UTF_8);
byte[] bytes = "The quick brown fox jumps over the lazy dog".getBytes(Internal.UTF_8);
assertInvalidSlice(bytes, bytes.length - 3, 4);
assertInvalidSlice(bytes, bytes.length, 1);
assertInvalidSlice(bytes, bytes.length + 1, 0);
@ -180,10 +208,14 @@ public class DecodeUtf8Test extends TestCase {
for (int i = 0; i < bytesAsInt.length; i++) {
bytes[i] = (byte) bytesAsInt[i];
}
assertInvalid(bytes);
assertInvalid(bytes, null);
}
private void assertInvalid(byte[] bytes) throws Exception {
// Attempts to decode the byte array in several ways and asserts that it always generates an
// exception. Allocating a direct ByteBuffer is slow, so the caller can optionally provide a
// buffer to reuse. If buffer is non-null, it must be a direct-allocated ByteBuffer of the
// appropriate size.
private void assertInvalid(byte[] bytes, ByteBuffer buffer) throws Exception {
try {
UNSAFE_PROCESSOR.decodeUtf8(bytes, 0, bytes.length);
fail();
@ -197,37 +229,24 @@ public class DecodeUtf8Test extends TestCase {
// Expected.
}
ByteBuffer direct = ByteBuffer.allocateDirect(bytes.length);
direct.put(bytes);
direct.flip();
if (buffer == null) {
buffer = ByteBuffer.allocateDirect(bytes.length);
}
buffer.put(bytes);
buffer.flip();
try {
UNSAFE_PROCESSOR.decodeUtf8(direct, 0, bytes.length);
UNSAFE_PROCESSOR.decodeUtf8(buffer, 0, bytes.length);
fail();
} catch (InvalidProtocolBufferException e) {
// Expected.
}
try {
SAFE_PROCESSOR.decodeUtf8(direct, 0, bytes.length);
fail();
} catch (InvalidProtocolBufferException e) {
// Expected.
}
ByteBuffer heap = ByteBuffer.allocate(bytes.length);
heap.put(bytes);
heap.flip();
try {
UNSAFE_PROCESSOR.decodeUtf8(heap, 0, bytes.length);
fail();
} catch (InvalidProtocolBufferException e) {
// Expected.
}
try {
SAFE_PROCESSOR.decodeUtf8(heap, 0, bytes.length);
SAFE_PROCESSOR.decodeUtf8(buffer, 0, bytes.length);
fail();
} catch (InvalidProtocolBufferException e) {
// Expected.
}
buffer.clear();
}
private void assertInvalidSlice(byte[] bytes, int index, int size) throws Exception {
@ -286,25 +305,31 @@ public class DecodeUtf8Test extends TestCase {
if (size == -1) {
size = bytes.length;
}
assertDecode(new String(bytes, index, size, Internal.UTF_8),
assertDecode(
new String(bytes, index, size, Internal.UTF_8),
UNSAFE_PROCESSOR.decodeUtf8(bytes, index, size));
assertDecode(new String(bytes, index, size, Internal.UTF_8),
assertDecode(
new String(bytes, index, size, Internal.UTF_8),
SAFE_PROCESSOR.decodeUtf8(bytes, index, size));
ByteBuffer direct = ByteBuffer.allocateDirect(bytes.length);
direct.put(bytes);
direct.flip();
assertDecode(new String(bytes, index, size, Internal.UTF_8),
assertDecode(
new String(bytes, index, size, Internal.UTF_8),
UNSAFE_PROCESSOR.decodeUtf8(direct, index, size));
assertDecode(new String(bytes, index, size, Internal.UTF_8),
assertDecode(
new String(bytes, index, size, Internal.UTF_8),
SAFE_PROCESSOR.decodeUtf8(direct, index, size));
ByteBuffer heap = ByteBuffer.allocate(bytes.length);
heap.put(bytes);
heap.flip();
assertDecode(new String(bytes, index, size, Internal.UTF_8),
assertDecode(
new String(bytes, index, size, Internal.UTF_8),
UNSAFE_PROCESSOR.decodeUtf8(heap, index, size));
assertDecode(new String(bytes, index, size, Internal.UTF_8),
assertDecode(
new String(bytes, index, size, Internal.UTF_8),
SAFE_PROCESSOR.decodeUtf8(heap, index, size));
}
@ -321,5 +346,4 @@ public class DecodeUtf8Test extends TestCase {
}
return codepoints;
}
}

View File

@ -36,6 +36,7 @@ import static com.google.protobuf.IsValidUtf8TestUtil.EXPECTED_ONE_BYTE_ROUNDTRI
import static com.google.protobuf.IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT;
import static com.google.protobuf.IsValidUtf8TestUtil.HEAP_NIO_FACTORY;
import static com.google.protobuf.IsValidUtf8TestUtil.LITERAL_FACTORY;
import static com.google.protobuf.IsValidUtf8TestUtil.ROPE_FACTORY;
import static com.google.protobuf.IsValidUtf8TestUtil.testBytes;
import com.google.protobuf.IsValidUtf8TestUtil.ByteStringFactory;
@ -61,6 +62,7 @@ public class IsValidUtf8Test {
testBytes(LITERAL_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
testBytes(HEAP_NIO_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
testBytes(DIRECT_NIO_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
testBytes(ROPE_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
}
/** Tests that round tripping of all two byte permutations work. */
@ -69,17 +71,16 @@ public class IsValidUtf8Test {
testBytes(LITERAL_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
testBytes(HEAP_NIO_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
testBytes(DIRECT_NIO_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
testBytes(ROPE_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
}
/** Tests that round tripping of all three byte permutations work. */
@Test
public void testIsValidUtf8_3Bytes() {
// Travis' OOM killer doesn't like this test
if (System.getenv("TRAVIS") == null) {
testBytes(LITERAL_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
testBytes(HEAP_NIO_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
testBytes(DIRECT_NIO_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
}
testBytes(LITERAL_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
testBytes(HEAP_NIO_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
testBytes(DIRECT_NIO_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
testBytes(ROPE_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
}
/**
@ -168,12 +169,14 @@ public class IsValidUtf8Test {
assertValidUtf8(LITERAL_FACTORY, bytes, false);
assertValidUtf8(HEAP_NIO_FACTORY, bytes, false);
assertValidUtf8(DIRECT_NIO_FACTORY, bytes, false);
assertValidUtf8(ROPE_FACTORY, bytes, false);
}
private void assertInvalidUtf8(int... bytes) {
assertValidUtf8(LITERAL_FACTORY, bytes, true);
assertValidUtf8(HEAP_NIO_FACTORY, bytes, true);
assertValidUtf8(DIRECT_NIO_FACTORY, bytes, true);
assertValidUtf8(ROPE_FACTORY, bytes, true);
}
private static ByteString asBytes(String s) {

View File

@ -35,16 +35,10 @@ import static com.google.common.truth.Truth.assertWithMessage;
import java.lang.ref.SoftReference;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.logging.Logger;
/**
* Shared testing code for {@link IsValidUtf8Test} and {@link IsValidUtf8FourByteTest}.
@ -53,8 +47,6 @@ import java.util.logging.Logger;
* @author martinrb@google.com (Martin Buchholz)
*/
final class IsValidUtf8TestUtil {
private static final Logger logger = Logger.getLogger(IsValidUtf8TestUtil.class.getName());
private IsValidUtf8TestUtil() {}
static interface ByteStringFactory {
@ -102,6 +94,29 @@ final class IsValidUtf8TestUtil {
}
};
static final ByteStringFactory ROPE_FACTORY =
new ByteStringFactory() {
// Seed the random number generator with 0 so that the tests are deterministic.
private final Random random = new Random(0);
@Override
public ByteString newByteString(byte[] bytes) {
// We split the byte array into three pieces (some possibly empty) by choosing two random
// cut points i and j.
int i = random.nextInt(bytes.length);
int j = random.nextInt(bytes.length);
if (j < i) {
int tmp = i;
i = j;
j = tmp;
}
return RopeByteString.newInstanceForTest(
ByteString.wrap(bytes, 0, i),
RopeByteString.newInstanceForTest(
ByteString.wrap(bytes, i, j - i), ByteString.wrap(bytes, j, bytes.length - j)));
}
};
// 128 - [chars 0x0000 to 0x007f]
static final long ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x007f - 0x0000 + 1;
@ -247,13 +262,11 @@ final class IsValidUtf8TestUtil {
*/
static void testBytes(
ByteStringFactory factory, int numBytes, long expectedCount, long start, long lim) {
Random rnd = new Random();
byte[] bytes = new byte[numBytes];
if (lim == -1) {
lim = 1L << (numBytes * 8);
}
long count = 0;
long countRoundTripped = 0;
for (long byteChar = start; byteChar < lim; byteChar++) {
long tmpByteChar = byteChar;
@ -271,166 +284,13 @@ final class IsValidUtf8TestUtil {
outputFailure(byteChar, bytes, bytesReencoded);
}
// Check agreement with static Utf8 methods.
// Check agreement with Utf8.isValidUtf8.
assertThat(Utf8.isValidUtf8(bytes)).isEqualTo(isRoundTrippable);
assertThat(Utf8.isValidUtf8(bytes, 0, numBytes)).isEqualTo(isRoundTrippable);
try {
assertThat(Utf8.decodeUtf8(bytes, 0, numBytes)).isEqualTo(s);
} catch (InvalidProtocolBufferException e) {
if (isRoundTrippable) {
System.out.println("Could not decode utf-8");
outputFailure(byteChar, bytes, bytesReencoded);
}
}
// Test partial sequences.
// Partition numBytes into three segments (not necessarily non-empty).
int i = rnd.nextInt(numBytes);
int j = rnd.nextInt(numBytes);
if (j < i) {
int tmp = i;
i = j;
j = tmp;
}
int state1 = Utf8.partialIsValidUtf8(Utf8.COMPLETE, bytes, 0, i);
int state2 = Utf8.partialIsValidUtf8(state1, bytes, i, j);
int state3 = Utf8.partialIsValidUtf8(state2, bytes, j, numBytes);
if (isRoundTrippable != (state3 == Utf8.COMPLETE)) {
System.out.printf("state=%04x %04x %04x i=%d j=%d%n", state1, state2, state3, i, j);
outputFailure(byteChar, bytes, bytesReencoded);
}
assertThat((state3 == Utf8.COMPLETE)).isEqualTo(isRoundTrippable);
// Test ropes built out of small partial sequences
ByteString rope =
RopeByteString.newInstanceForTest(
bs.substring(0, i),
RopeByteString.newInstanceForTest(bs.substring(i, j), bs.substring(j, numBytes)));
assertThat(rope.getClass()).isSameInstanceAs(RopeByteString.class);
ByteString[] byteStrings = {bs, bs.substring(0, numBytes), rope};
for (ByteString x : byteStrings) {
assertThat(x.isValidUtf8()).isEqualTo(isRoundTrippable);
assertThat(x.partialIsValidUtf8(Utf8.COMPLETE, 0, numBytes)).isEqualTo(state3);
assertThat(x.partialIsValidUtf8(Utf8.COMPLETE, 0, i)).isEqualTo(state1);
assertThat(x.substring(0, i).partialIsValidUtf8(Utf8.COMPLETE, 0, i)).isEqualTo(state1);
assertThat(x.partialIsValidUtf8(state1, i, j - i)).isEqualTo(state2);
assertThat(x.substring(i, j).partialIsValidUtf8(state1, 0, j - i)).isEqualTo(state2);
assertThat(x.partialIsValidUtf8(state2, j, numBytes - j)).isEqualTo(state3);
assertThat(x.substring(j, numBytes).partialIsValidUtf8(state2, 0, numBytes - j))
.isEqualTo(state3);
}
// ByteString reduplication should not affect its UTF-8 validity.
ByteString ropeADope = RopeByteString.newInstanceForTest(bs, bs.substring(0, numBytes));
assertThat(ropeADope.isValidUtf8()).isEqualTo(isRoundTrippable);
if (isRoundTrippable) {
countRoundTripped++;
}
count++;
if (byteChar != 0 && byteChar % 1000000L == 0) {
logger.info("Processed " + (byteChar / 1000000L) + " million characters");
}
}
logger.info("Round tripped " + countRoundTripped + " of " + count);
assertThat(countRoundTripped).isEqualTo(expectedCount);
}
/**
* Variation of {@link #testBytes} that does less allocation using the low-level encoders/decoders
* directly. Checked in because it's useful for debugging when trying to process bytes faster, but
* since it doesn't use the actual String class, it's possible for incompatibilities to develop
* (although unlikely).
*
* @param factory the factory for {@link ByteString} instances.
* @param numBytes the number of bytes in the byte array
* @param expectedCount the expected number of roundtrippable permutations
* @param start the starting bytes encoded as a long as big-endian
* @param lim the limit of bytes to process encoded as a long as big-endian, or -1 to mean the max
* limit for numBytes
*/
static void testBytesUsingByteBuffers(
ByteStringFactory factory, int numBytes, long expectedCount, long start, long lim) {
CharsetDecoder decoder =
Internal.UTF_8
.newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE);
CharsetEncoder encoder =
Internal.UTF_8
.newEncoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE);
byte[] bytes = new byte[numBytes];
int maxChars = (int) (decoder.maxCharsPerByte() * numBytes) + 1;
char[] charsDecoded = new char[(int) (decoder.maxCharsPerByte() * numBytes) + 1];
int maxBytes = (int) (encoder.maxBytesPerChar() * maxChars) + 1;
byte[] bytesReencoded = new byte[maxBytes];
ByteBuffer bb = ByteBuffer.wrap(bytes);
CharBuffer cb = CharBuffer.wrap(charsDecoded);
ByteBuffer bbReencoded = ByteBuffer.wrap(bytesReencoded);
if (lim == -1) {
lim = 1L << (numBytes * 8);
}
long count = 0;
long countRoundTripped = 0;
for (long byteChar = start; byteChar < lim; byteChar++) {
bb.rewind();
bb.limit(bytes.length);
cb.rewind();
cb.limit(charsDecoded.length);
bbReencoded.rewind();
bbReencoded.limit(bytesReencoded.length);
encoder.reset();
decoder.reset();
long tmpByteChar = byteChar;
for (int i = 0; i < bytes.length; i++) {
bytes[bytes.length - i - 1] = (byte) tmpByteChar;
tmpByteChar = tmpByteChar >> 8;
}
boolean isRoundTrippable = factory.newByteString(bytes).isValidUtf8();
CoderResult result = decoder.decode(bb, cb, true);
assertThat(result.isError()).isFalse();
result = decoder.flush(cb);
assertThat(result.isError()).isFalse();
int charLen = cb.position();
cb.rewind();
cb.limit(charLen);
result = encoder.encode(cb, bbReencoded, true);
assertThat(result.isError()).isFalse();
result = encoder.flush(bbReencoded);
assertThat(result.isError()).isFalse();
boolean bytesEqual = true;
int bytesLen = bbReencoded.position();
if (bytesLen != numBytes) {
bytesEqual = false;
} else {
for (int i = 0; i < numBytes; i++) {
if (bytes[i] != bytesReencoded[i]) {
bytesEqual = false;
break;
}
}
}
if (bytesEqual != isRoundTrippable) {
outputFailure(byteChar, bytes, bytesReencoded, bytesLen);
}
count++;
if (isRoundTrippable) {
countRoundTripped++;
}
if (byteChar != 0 && byteChar % 1000000 == 0) {
logger.info("Processed " + (byteChar / 1000000) + " million characters");
}
}
logger.info("Round tripped " + countRoundTripped + " of " + count);
assertThat(countRoundTripped).isEqualTo(expectedCount);
}

View File

@ -380,4 +380,34 @@ public class MessageTest {
result.getDescriptorForType().findFieldByName("repeated_foreign_message")))
.isEqualTo(2);
}
@Test
public void testPreservesFloatingPointNegative0() throws Exception {
proto3_unittest.UnittestProto3.TestAllTypes message =
proto3_unittest.UnittestProto3.TestAllTypes.newBuilder()
.setOptionalFloat(-0.0f)
.setOptionalDouble(-0.0)
.build();
assertThat(
proto3_unittest.UnittestProto3.TestAllTypes.parseFrom(
message.toByteString(), ExtensionRegistry.getEmptyRegistry()))
.isEqualTo(message);
}
@Test
public void testNegative0FloatingPointEquality() throws Exception {
// Like Double#equals and Float#equals, we treat -0.0 as not being equal to +0.0 even though
// IEEE 754 mandates that they are equivalent. This test asserts that behavior.
proto3_unittest.UnittestProto3.TestAllTypes message1 =
proto3_unittest.UnittestProto3.TestAllTypes.newBuilder()
.setOptionalFloat(-0.0f)
.setOptionalDouble(-0.0)
.build();
proto3_unittest.UnittestProto3.TestAllTypes message2 =
proto3_unittest.UnittestProto3.TestAllTypes.newBuilder()
.setOptionalFloat(0.0f)
.setOptionalDouble(0.0)
.build();
assertThat(message1).isNotEqualTo(message2);
}
}

View File

@ -316,7 +316,6 @@ public class ServiceTest {
}
@Override
@SuppressWarnings("unchecked")
public boolean matches(Object actual) {
if (!(actual instanceof RpcCallback)) {
return false;

View File

@ -41,7 +41,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Test @{link TextFormatParseInfoTree}. */
/** Test {@link TextFormatParseInfoTree}. */
@RunWith(JUnit4.class)
public class TextFormatParseInfoTreeTest {

View File

@ -37,7 +37,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Test @{link TextFormatParseLocation}. */
/** Test {@link TextFormatParseLocation}. */
@RunWith(JUnit4.class)
public class TextFormatParseLocationTest {

View File

@ -1815,4 +1815,15 @@ public class TextFormatTest {
+ "}\n";
assertThat(TextFormat.printer().printToString(message)).isEqualTo(text);
}
@Test
public void testPreservesFloatingPointNegative0() throws Exception {
proto3_unittest.UnittestProto3.TestAllTypes message =
proto3_unittest.UnittestProto3.TestAllTypes.newBuilder()
.setOptionalFloat(-0.0f)
.setOptionalDouble(-0.0)
.build();
assertThat(TextFormat.printer().printToString(message))
.isEqualTo("optional_float: -0.0\noptional_double: -0.0\n");
}
}

View File

@ -2752,6 +2752,36 @@ public class LiteTest {
.isTrue();
}
@Test
public void testPreservesFloatingPointNegative0() throws Exception {
proto3_unittest.UnittestProto3.TestAllTypes message =
proto3_unittest.UnittestProto3.TestAllTypes.newBuilder()
.setOptionalFloat(-0.0f)
.setOptionalDouble(-0.0)
.build();
assertThat(
proto3_unittest.UnittestProto3.TestAllTypes.parseFrom(
message.toByteString(), ExtensionRegistryLite.getEmptyRegistry()))
.isEqualTo(message);
}
@Test
public void testNegative0FloatingPointEquality() throws Exception {
// Like Double#equals and Float#equals, we treat -0.0 as not being equal to +0.0 even though
// IEEE 754 mandates that they are equivalent. This test asserts that behavior.
proto3_unittest.UnittestProto3.TestAllTypes message1 =
proto3_unittest.UnittestProto3.TestAllTypes.newBuilder()
.setOptionalFloat(-0.0f)
.setOptionalDouble(-0.0)
.build();
proto3_unittest.UnittestProto3.TestAllTypes message2 =
proto3_unittest.UnittestProto3.TestAllTypes.newBuilder()
.setOptionalFloat(0.0f)
.setOptionalDouble(0.0)
.build();
assertThat(message1).isNotEqualTo(message2);
}
private String encodeHex(ByteString bytes) {
String hexDigits = "0123456789abcdef";
StringBuilder stringBuilder = new StringBuilder(bytes.size() * 2);

View File

@ -14,6 +14,7 @@ java_library(
"//external:error_prone_annotations",
"//external:j2objc_annotations",
"//external:gson",
"//external:jsr305",
"//external:guava",
"//java/core",
"//java/lite",

View File

@ -46,6 +46,7 @@ import com.google.protobuf.Message;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nullable;
/**
* Utility helper functions to work with {@link com.google.protobuf.FieldMask}.
@ -230,10 +231,8 @@ public final class FieldMaskUtil {
return isValid(descriptor, path);
}
/**
* Checks whether paths in a given fields mask are valid.
*/
public static boolean isValid(Descriptor descriptor, String path) {
/** Checks whether paths in a given fields mask are valid. */
public static boolean isValid(@Nullable Descriptor descriptor, String path) {
String[] parts = path.split(FIELD_SEPARATOR_REGEX);
if (parts.length == 0) {
return false;

View File

@ -88,6 +88,7 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Logger;
import javax.annotation.Nullable;
/**
* Utility classes to convert protobuf messages to/from JSON format. The JSON
@ -521,10 +522,12 @@ public class JsonFormat {
* Find a type by its full name. Returns null if it cannot be found in this {@link
* TypeRegistry}.
*/
@Nullable
public Descriptor find(String name) {
return types.get(name);
}
@Nullable
Descriptor getDescriptorForTypeUrl(String typeUrl) throws InvalidProtocolBufferException {
return find(getTypeName(typeUrl));
}
@ -546,7 +549,7 @@ public class JsonFormat {
*/
@CanIgnoreReturnValue
public Builder add(Descriptor messageType) {
if (types == null) {
if (built) {
throw new IllegalStateException("A TypeRegistry.Builder can only be used once.");
}
addFile(messageType.getFile());
@ -559,7 +562,7 @@ public class JsonFormat {
*/
@CanIgnoreReturnValue
public Builder add(Iterable<Descriptor> messageTypes) {
if (types == null) {
if (built) {
throw new IllegalStateException("A TypeRegistry.Builder can only be used once.");
}
for (Descriptor type : messageTypes) {
@ -573,10 +576,8 @@ public class JsonFormat {
* one Builder.
*/
public TypeRegistry build() {
TypeRegistry result = new TypeRegistry(types);
// Make sure the built {@link TypeRegistry} is immutable.
types = null;
return result;
built = true;
return new TypeRegistry(types);
}
private void addFile(FileDescriptor file) {
@ -607,6 +608,7 @@ public class JsonFormat {
private final Set<String> files = new HashSet<String>();
private Map<String, Descriptor> types = new HashMap<String, Descriptor>();
private boolean built = false;
}
}
@ -984,7 +986,7 @@ public class JsonFormat {
}
/** Prints a regular message with an optional type URL. */
private void print(MessageOrBuilder message, String typeUrl) throws IOException {
private void print(MessageOrBuilder message, @Nullable String typeUrl) throws IOException {
generator.print("{" + blankOrNewLine);
generator.indent();
@ -1340,7 +1342,9 @@ public class JsonFormat {
throw e;
} catch (Exception e) {
// We convert all exceptions from JSON parsing to our own exceptions.
throw new InvalidProtocolBufferException(e.getMessage());
InvalidProtocolBufferException toThrow = new InvalidProtocolBufferException(e.getMessage());
toThrow.initCause(e);
throw toThrow;
}
}
@ -1899,6 +1903,7 @@ public class JsonFormat {
}
}
@Nullable
private EnumValueDescriptor parseEnum(EnumDescriptor enumDescriptor, JsonElement json)
throws InvalidProtocolBufferException {
String value = json.getAsString();
@ -1926,6 +1931,7 @@ public class JsonFormat {
return result;
}
@Nullable
private Object parseFieldValue(FieldDescriptor field, JsonElement json, Message.Builder builder)
throws InvalidProtocolBufferException {
if (json instanceof JsonNull) {

View File

@ -1887,4 +1887,12 @@ public class JsonFormatTest {
.print(message))
.isEqualTo("{\n" + " \"optionalBool\": false\n" + "}");
}
@Test
public void testPreservesFloatingPointNegative0() throws Exception {
TestAllTypes message =
TestAllTypes.newBuilder().setOptionalFloat(-0.0f).setOptionalDouble(-0.0).build();
assertThat(JsonFormat.printer().print(message))
.isEqualTo("{\n \"optionalFloat\": -0.0,\n \"optionalDouble\": -0.0\n}");
}
}

View File

@ -394,7 +394,7 @@ describe('binaryUtilsTest', function() {
// corner cases
test(0.9999999762949594, 0x3f800000);
test(7.99999999999999, 0x41000000);
test(Math.sin(30 * Math.PI / 180), 0x3f000000); // sin(30 degrees)
test(Math.sin(30 * Math.PI / 180), 0x3f000000); // sin(30 degrees)
// Various positive values.
var cursor = f32_eps * 10;

View File

@ -1,6 +1,8 @@
{
"dependency_tree": {
"__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": 1033791982,
"__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL",
"__INPUT_ARTIFACTS_HASH": 1907885757,
"__RESOLVED_ARTIFACTS_HASH": 375457873,
"conflict_resolution": {
"com.google.errorprone:error_prone_annotations:2.3.2": "com.google.errorprone:error_prone_annotations:2.5.1",
"junit:junit:4.12": "junit:junit:4.13.1"
@ -201,24 +203,6 @@
"sha256": "b3dd1cf5019f942d8cc2afad0aa6aef4b21532446fe90a6b68d567e3389763dd",
"url": "https://repo1.maven.org/maven2/org/easymock/easymock/3.2/easymock-3.2.jar"
},
{
"coord": "org.easymock:easymockclassextension:3.2",
"dependencies": [
"org.easymock:easymock:3.2",
"cglib:cglib-nodep:2.2.2",
"org.objenesis:objenesis:1.3"
],
"directDependencies": [
"org.easymock:easymock:3.2"
],
"file": "v1/https/repo1.maven.org/maven2/org/easymock/easymockclassextension/3.2/easymockclassextension-3.2.jar",
"mirror_urls": [
"https://repo1.maven.org/maven2/org/easymock/easymockclassextension/3.2/easymockclassextension-3.2.jar",
"https://repo.maven.apache.org/maven2/org/easymock/easymockclassextension/3.2/easymockclassextension-3.2.jar"
],
"sha256": "e2aeb3ecec87d859b2f3072985d4b15873558bcf6410f422db0c0c5194c76c87",
"url": "https://repo1.maven.org/maven2/org/easymock/easymockclassextension/3.2/easymockclassextension-3.2.jar"
},
{
"coord": "org.hamcrest:hamcrest-core:1.3",
"dependencies": [],

View File

@ -41,46 +41,15 @@ try:
# The compile-time constants in the _api_implementation module can be used to
# switch to a certain implementation of the Python API at build time.
_api_version = _api_implementation.api_version
_proto_extension_modules_exist_in_build = True
except ImportError:
_api_version = -1 # Unspecified by compiler flags.
_proto_extension_modules_exist_in_build = False
if _api_version == 1:
raise ValueError('api_version=1 is no longer supported.')
if _api_version < 0: # Still unspecified?
try:
# The presence of this module in a build allows the proto implementation to
# be upgraded merely via build deps rather than a compiler flag or the
# runtime environment variable.
# pylint: disable=g-import-not-at-top
from google.protobuf import _use_fast_cpp_protos
# Work around a known issue in the classic bootstrap .par import hook.
if not _use_fast_cpp_protos:
raise ImportError('_use_fast_cpp_protos import succeeded but was None')
del _use_fast_cpp_protos
_api_version = 2
from google.protobuf import use_pure_python
raise RuntimeError(
'Conflicting deps on both :use_fast_cpp_protos and :use_pure_python.\n'
' go/build_deps_on_BOTH_use_fast_cpp_protos_AND_use_pure_python\n'
'This should be impossible via a link error at build time...')
except ImportError:
try:
# pylint: disable=g-import-not-at-top
from google.protobuf import use_pure_python
del use_pure_python # Avoids a pylint error and namespace pollution.
_api_version = 0
except ImportError:
# 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')
_default_implementation_type = ('cpp' if _api_version > 0 else 'python')
# This environment variable can be used to switch to a certain implementation
# of the Python API, overriding the compile-time constants in the
@ -97,21 +66,6 @@ if 'PyPy' in sys.version and _implementation_type == 'cpp':
'Falling back to the python implementation.')
_implementation_type = 'python'
# This environment variable can be used to switch between the two
# 'cpp' implementations, overriding the compile-time constants in the
# _api_implementation module. Right now only '2' is supported. Any other
# value will cause an error to be raised.
_implementation_version_str = os.getenv(
'PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION', '2')
if _implementation_version_str != '2':
raise ValueError(
'unsupported PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION: "' +
_implementation_version_str + '" (supported versions: 2)'
)
_implementation_version = int(_implementation_version_str)
# Detect if serialization should be deterministic by default
try:
@ -150,7 +104,7 @@ def _SetType(implementation_type):
# See comment on 'Type' above.
def Version():
return _implementation_version
return 2
# For internal use only

View File

@ -359,6 +359,14 @@ class Message(object):
"""
raise NotImplementedError
@classmethod
def FromString(cls, s):
raise NotImplementedError
@staticmethod
def RegisterExtension(extension_handle):
raise NotImplementedError
def _SetListener(self, message_listener):
"""Internal method used by the protocol message implementation.
Clients should not call this directly.

View File

@ -1919,7 +1919,9 @@ static PyObject* MergeFromString(CMessage* self, PyObject* arg) {
// explicit in our correctness checks.
if (ptr == nullptr || ctx.BytesUntilLimit(ptr) < 0) {
// Parse error or the parser overshoot the limit.
PyErr_Format(DecodeError_class, "Error parsing message");
PyErr_Format(
DecodeError_class, "Error parsing message with type '%s'",
self->GetMessageClass()->message_descriptor->full_name().c_str());
return NULL;
}
// ctx has an explicit limit set (length of string_view), so we have to

View File

@ -211,11 +211,11 @@ if __name__ == '__main__':
extra_compile_args = []
if sys.platform != 'win32':
extra_compile_args.append('-Wno-write-strings')
extra_compile_args.append('-Wno-invalid-offsetof')
extra_compile_args.append('-Wno-sign-compare')
extra_compile_args.append('-Wno-unused-variable')
extra_compile_args.append('-std=c++11')
extra_compile_args.append('-Wno-write-strings')
extra_compile_args.append('-Wno-invalid-offsetof')
extra_compile_args.append('-Wno-sign-compare')
extra_compile_args.append('-Wno-unused-variable')
extra_compile_args.append('-std=c++11')
if sys.platform == 'darwin':
extra_compile_args.append("-Wno-shorten-64-to-32");
@ -285,21 +285,20 @@ if __name__ == '__main__':
maintainer_email='protobuf@googlegroups.com',
license='3-Clause BSD License',
classifiers=[
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
],
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
],
namespace_packages=['google'],
packages=find_packages(
exclude=[
'import_test_package',
'protobuf_distutils',
],
),
],),
test_suite='google.protobuf.internal',
cmdclass={
'clean': clean,
@ -309,5 +308,5 @@ if __name__ == '__main__':
},
install_requires=install_requires,
ext_modules=ext_module_list,
python_requires='>=3.5',
python_requires=">=3.5",
)

View File

@ -18,7 +18,7 @@ else
PTHREAD_DEF =
endif
PROTOBUF_VERSION = 29:1:0
PROTOBUF_VERSION = 28:3:0
if GCC
# Turn on all warnings except for sign comparison (we ignore sign comparison
@ -145,6 +145,7 @@ nobase_include_HEADERS = \
google/protobuf/reflection.h \
google/protobuf/reflection_ops.h \
google/protobuf/repeated_field.h \
google/protobuf/repeated_ptr_field.h \
google/protobuf/service.h \
google/protobuf/source_context.pb.h \
google/protobuf/struct.pb.h \
@ -210,6 +211,7 @@ libprotobuf_lite_la_SOURCES = \
google/protobuf/message_lite.cc \
google/protobuf/parse_context.cc \
google/protobuf/repeated_field.cc \
google/protobuf/repeated_ptr_field.cc \
google/protobuf/string_member_robber.h \
google/protobuf/stubs/bytestream.cc \
google/protobuf/stubs/common.cc \
@ -541,8 +543,8 @@ EXTRA_DIST = \
google/protobuf/compiler/package_info.h \
google/protobuf/compiler/ruby/ruby_generated_code.proto \
google/protobuf/compiler/ruby/ruby_generated_code_pb.rb \
google/protobuf/compiler/ruby/ruby_generated_code_proto2_import.proto \
google/protobuf/compiler/ruby/ruby_generated_code_proto2.proto \
google/protobuf/compiler/ruby/ruby_generated_code_proto2_import.proto \
google/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb \
google/protobuf/compiler/ruby/ruby_generated_pkg_explicit.proto \
google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy.proto \

View File

@ -202,13 +202,6 @@ class PROTOBUF_EXPORT SerialArena {
void (*cleanup)(void*); // Function pointer to the destructor or deleter.
};
// Creates a new SerialArena inside mem using the remaining memory as for
// future allocations.
static SerialArena* New(SerialArena::Memory mem, void* owner);
// Free SerialArena returning the memory passed in to New
template <typename Deallocator>
Memory Free(Deallocator deallocator);
void CleanupList();
uint64_t SpaceAllocated() const {
return space_allocated_.load(std::memory_order_relaxed);
@ -281,6 +274,16 @@ class PROTOBUF_EXPORT SerialArena {
void set_next(SerialArena* next) { next_ = next; }
private:
friend class ThreadSafeArena;
friend class ArenaBenchmark;
// Creates a new SerialArena inside mem using the remaining memory as for
// future allocations.
static SerialArena* New(SerialArena::Memory mem, void* owner);
// Free SerialArena returning the memory passed in to New
template <typename Deallocator>
Memory Free(Deallocator deallocator);
// Blocks are variable length malloc-ed objects. The following structure
// describes the common header for all blocks.
struct Block {

View File

@ -256,6 +256,12 @@ void ArenaStringPtr::ClearToDefault(const LazyString& default_value,
}
}
inline void SetStrWithHeapBuffer(std::string* str, ArenaStringPtr* s) {
TaggedPtr<std::string> res;
res.Set(str);
s->UnsafeSetTaggedPointer(res);
}
const char* EpsCopyInputStream::ReadArenaString(const char* ptr,
ArenaStringPtr* s,
Arena* arena) {
@ -264,13 +270,11 @@ const char* EpsCopyInputStream::ReadArenaString(const char* ptr,
int size = ReadSize(&ptr);
if (!ptr) return nullptr;
auto str = Arena::Create<std::string>(arena);
auto* str = Arena::Create<std::string>(arena);
ptr = ReadString(ptr, size, str);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
TaggedPtr<std::string> res;
res.Set(str);
s->UnsafeSetTaggedPointer(res);
SetStrWithHeapBuffer(str, s);
return ptr;
}

View File

@ -334,106 +334,6 @@ void RepeatedEnumFieldGenerator::GenerateConstructorCode(
// Not needed for repeated fields.
}
void RepeatedEnumFieldGenerator::GenerateMergeFromCodedStream(
io::Printer* printer) const {
Formatter format(printer, variables_);
// Don't use ReadRepeatedPrimitive here so that the enum can be validated.
format(
"int value = 0;\n"
"DO_((::$proto_ns$::internal::WireFormatLite::ReadPrimitive<\n"
" int, ::$proto_ns$::internal::WireFormatLite::TYPE_ENUM>(\n"
" input, &value)));\n");
if (HasPreservingUnknownEnumSemantics(descriptor_)) {
format("add_$name$(static_cast< $type$ >(value));\n");
} else {
format(
"if ($type$_IsValid(value)) {\n"
" add_$name$(static_cast< $type$ >(value));\n");
if (UseUnknownFieldSet(descriptor_->file(), options_)) {
format(
"} else {\n"
" mutable_unknown_fields()->AddVarint(\n"
" $number$, static_cast<$uint64$>(value));\n");
} else {
format(
"} else {\n"
" unknown_fields_stream.WriteVarint32(tag);\n"
" unknown_fields_stream.WriteVarint32(\n"
" static_cast<$uint32$>(value));\n");
}
format("}\n");
}
}
void RepeatedEnumFieldGenerator::GenerateMergeFromCodedStreamWithPacking(
io::Printer* printer) const {
Formatter format(printer, variables_);
if (!descriptor_->is_packed()) {
// This path is rarely executed, so we use a non-inlined implementation.
if (HasPreservingUnknownEnumSemantics(descriptor_)) {
format(
"DO_((::$proto_ns$::internal::"
"WireFormatLite::ReadPackedEnumPreserveUnknowns(\n"
" input,\n"
" $number$,\n"
" nullptr,\n"
" nullptr,\n"
" this->_internal_mutable_$name$())));\n");
} else if (UseUnknownFieldSet(descriptor_->file(), options_)) {
format(
"DO_((::$proto_ns$::internal::WireFormat::"
"ReadPackedEnumPreserveUnknowns(\n"
" input,\n"
" $number$,\n"
" $type$_IsValid,\n"
" mutable_unknown_fields(),\n"
" this->_internal_mutable_$name$())));\n");
} else {
format(
"DO_((::$proto_ns$::internal::"
"WireFormatLite::ReadPackedEnumPreserveUnknowns(\n"
" input,\n"
" $number$,\n"
" $type$_IsValid,\n"
" &unknown_fields_stream,\n"
" this->_internal_mutable_$name$())));\n");
}
} else {
format(
"$uint32$ length;\n"
"DO_(input->ReadVarint32(&length));\n"
"::$proto_ns$::io::CodedInputStream::Limit limit = "
"input->PushLimit(static_cast<int>(length));\n"
"while (input->BytesUntilLimit() > 0) {\n"
" int value = 0;\n"
" DO_((::$proto_ns$::internal::WireFormatLite::ReadPrimitive<\n"
" int, ::$proto_ns$::internal::WireFormatLite::TYPE_ENUM>(\n"
" input, &value)));\n");
if (HasPreservingUnknownEnumSemantics(descriptor_)) {
format(" add_$name$(static_cast< $type$ >(value));\n");
} else {
format(
" if ($type$_IsValid(value)) {\n"
" _internal_add_$name$(static_cast< $type$ >(value));\n"
" } else {\n");
if (UseUnknownFieldSet(descriptor_->file(), options_)) {
format(
" mutable_unknown_fields()->AddVarint(\n"
" $number$, static_cast<$uint64$>(value));\n");
} else {
format(
" unknown_fields_stream.WriteVarint32(tag);\n"
" unknown_fields_stream.WriteVarint32(\n"
" static_cast<$uint32$>(value));\n");
}
format(" }\n");
}
format(
"}\n"
"input->PopLimit(limit);\n");
}
}
void RepeatedEnumFieldGenerator::GenerateSerializeWithCachedSizesToArray(
io::Printer* printer) const {
Formatter format(printer, variables_);

View File

@ -98,8 +98,6 @@ class RepeatedEnumFieldGenerator : public FieldGenerator {
void GenerateSwappingCode(io::Printer* printer) const override;
void GenerateConstructorCode(io::Printer* printer) const override;
void GenerateCopyConstructorCode(io::Printer* printer) const override {}
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const;
void GenerateSerializeWithCachedSizesToArray(
io::Printer* printer) const override;
void GenerateByteSize(io::Printer* printer) const override;

View File

@ -340,7 +340,7 @@ FieldGenerator* FieldGeneratorMap::MakeGenerator(
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_MESSAGE:
if (field->is_map()) {
return new MapFieldGenerator(field, options);
return new MapFieldGenerator(field, options, scc_analyzer);
} else {
return new RepeatedMessageFieldGenerator(field, options,
scc_analyzer);

View File

@ -181,6 +181,10 @@ class FieldGenerator {
// are placed in the message's ByteSize() method.
virtual void GenerateByteSize(io::Printer* printer) const = 0;
// Generates lines to call IsInitialized() for eligible message fields. Non
// message fields won't need to override this function.
virtual void GenerateIsInitialized(io::Printer* printer) const {}
virtual bool IsInlined() const { return false; }
void SetHasBitIndex(int32_t has_bit_index);

View File

@ -743,6 +743,27 @@ class PROTOC_EXPORT Formatter {
void Outdent() const { printer_->Outdent(); }
io::Printer* printer() const { return printer_; }
class PROTOC_EXPORT ScopedIndenter {
public:
explicit ScopedIndenter(Formatter* format) : format_(format) {
format_->Indent();
}
~ScopedIndenter() { format_->Outdent(); }
private:
Formatter* format_;
};
PROTOBUF_NODISCARD ScopedIndenter ScopedIndent() {
return ScopedIndenter(this);
}
template <typename... Args>
PROTOBUF_NODISCARD ScopedIndenter ScopedIndent(const char* format,
const Args&&... args) {
(*this)(format, static_cast<Args&&>(args)...);
return ScopedIndenter(this);
}
class PROTOC_EXPORT SaveState {
public:
explicit SaveState(Formatter* format)

View File

@ -84,8 +84,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
}
MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
const Options& options)
: FieldGenerator(descriptor, options) {
const Options& options,
MessageSCCAnalyzer* scc_analyzer)
: FieldGenerator(descriptor, options),
has_required_fields_(
scc_analyzer->HasRequiredFields(descriptor->message_type())) {
SetMessageVariables(descriptor, &variables_, options);
}
@ -293,6 +296,15 @@ void MapFieldGenerator::GenerateByteSize(io::Printer* printer) const {
"}\n");
}
void MapFieldGenerator::GenerateIsInitialized(io::Printer* printer) const {
if (!has_required_fields_) return;
Formatter format(printer, variables_);
format(
"if (!::$proto_ns$::internal::AllAreInitialized($name$_)) return "
"false;\n");
}
void MapFieldGenerator::GenerateConstinitInitializer(
io::Printer* printer) const {
Formatter format(printer, variables_);

View File

@ -34,6 +34,7 @@
#include <map>
#include <string>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/compiler/cpp/cpp_message_field.h>
namespace google {
@ -43,8 +44,9 @@ namespace cpp {
class MapFieldGenerator : public FieldGenerator {
public:
MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options);
~MapFieldGenerator();
MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options,
MessageSCCAnalyzer* scc_analyzer);
~MapFieldGenerator() override;
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const override;
@ -58,10 +60,13 @@ class MapFieldGenerator : public FieldGenerator {
void GenerateSerializeWithCachedSizesToArray(
io::Printer* printer) const override;
void GenerateByteSize(io::Printer* printer) const override;
void GenerateIsInitialized(io::Printer* printer) const override;
void GenerateConstinitInitializer(io::Printer* printer) const override;
bool GenerateArenaDestructorCode(io::Printer* printer) const override;
private:
const bool has_required_fields_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
};

View File

@ -230,12 +230,22 @@ bool EmitFieldNonDefaultCondition(io::Printer* printer,
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
// Message fields still have has_$name$() methods.
format("if ($prefix$_internal_has_$name$()) {\n");
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE ||
field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT) {
// Handle float comparison to prevent -Wfloat-equal warnings
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT) {
format(
"if (!($prefix$_internal_$name$() <= 0 && $prefix$_internal_$name$() "
">= 0)) {\n");
"static_assert(sizeof(uint32_t) == sizeof(float), \"Code assumes "
"uint32_t and float are the same size.\");\n"
"float tmp_$name$ = $prefix$_internal_$name$();\n"
"uint32_t raw_$name$;\n"
"memcpy(&raw_$name$, &tmp_$name$, sizeof(tmp_$name$));\n"
"if (raw_$name$ != 0) {\n");
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) {
format(
"static_assert(sizeof(uint64_t) == sizeof(double), \"Code assumes "
"uint64_t and double are the same size.\");\n"
"double tmp_$name$ = $prefix$_internal_$name$();\n"
"uint64_t raw_$name$;\n"
"memcpy(&raw_$name$, &tmp_$name$, sizeof(tmp_$name$));\n"
"if (raw_$name$ != 0) {\n");
} else {
format("if ($prefix$_internal_$name$() != 0) {\n");
}
@ -2737,19 +2747,22 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(
// Some information about a field is in the pdproto profile. The profile is
// only available at compile time. So we embed such information in the
// offset of the field, so that the information is available when reflective
// accessing the field at run time.
// offset of the field, so that the information is available when
// reflectively accessing the field at run time.
//
// Embed whether the field is used to the MSB of the offset.
if (!IsFieldUsed(field, options_)) {
format(" | 0x80000000u, // unused\n");
} else if (IsEagerlyVerifiedLazy(field, options_, scc_analyzer_)) {
format(" | 0x1u, // eagerly verified lazy\n");
} else if (IsStringInlined(field, options_)) {
format(" | 0x1u, // inlined\n");
} else {
format(",\n");
format(" | 0x80000000u // unused\n");
}
// Embed whether the field is eagerly verified lazy or inlined string to the
// LSB of the offset.
if (IsEagerlyVerifiedLazy(field, options_, scc_analyzer_)) {
format(" | 0x1u // eagerly verified lazy\n");
} else if (IsStringInlined(field, options_)) {
format(" | 0x1u // inlined\n");
}
format(",\n");
}
int count = 0;
@ -4513,42 +4526,7 @@ void MessageGenerator::GenerateIsInitialized(io::Printer* printer) {
// Now check that all non-oneof embedded messages are initialized.
for (auto field : optimized_order_) {
// TODO(ckennelly): Push this down into a generator?
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
!ShouldIgnoreRequiredFieldCheck(field, options_) &&
scc_analyzer_->HasRequiredFields(field->message_type())) {
if (field->is_repeated()) {
if (IsImplicitWeakField(field, options_, scc_analyzer_)) {
format(
"if "
"(!::$proto_ns$::internal::AllAreInitializedWeak($1$_.weak)"
")"
" return false;\n",
FieldName(field));
} else {
format(
"if (!::$proto_ns$::internal::AllAreInitialized($1$_))"
" return false;\n",
FieldName(field));
}
} else if (field->options().weak()) {
continue;
} else if (IsEagerlyVerifiedLazy(field, options_, scc_analyzer_)) {
GOOGLE_CHECK(!field->real_containing_oneof());
format(
"if (_internal_has_$1$()) {\n"
" if (!$1$().IsInitialized()) return false;\n"
"}\n",
FieldName(field));
} else {
GOOGLE_CHECK(!field->real_containing_oneof());
format(
"if (_internal_has_$1$()) {\n"
" if (!$1$_->IsInitialized()) return false;\n"
"}\n",
FieldName(field));
}
}
field_generators_.get(field).GenerateIsInitialized(printer);
}
if (num_weak_fields_) {
// For Weak fields.
@ -4576,23 +4554,9 @@ void MessageGenerator::GenerateIsInitialized(io::Printer* printer) {
for (auto field : FieldRange(oneof)) {
format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true));
format.Indent();
if (!IsFieldStripped(field, options_) &&
field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
!ShouldIgnoreRequiredFieldCheck(field, options_) &&
scc_analyzer_->HasRequiredFields(field->message_type())) {
GOOGLE_CHECK(!(field->options().weak() || !field->real_containing_oneof()));
if (field->options().weak()) {
// Just skip.
} else {
format(
"if (has_$1$()) {\n"
" if (!this->$1$().IsInitialized()) return false;\n"
"}\n",
FieldName(field));
}
if (!IsFieldStripped(field, options_)) {
field_generators_.get(field).GenerateIsInitialized(printer);
}
format("break;\n");
format.Outdent();
format("}\n");

View File

@ -87,7 +87,9 @@ MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor,
MessageSCCAnalyzer* scc_analyzer)
: FieldGenerator(descriptor, options),
implicit_weak_field_(
IsImplicitWeakField(descriptor, options, scc_analyzer)) {
IsImplicitWeakField(descriptor, options, scc_analyzer)),
has_required_fields_(
scc_analyzer->HasRequiredFields(descriptor->message_type())) {
SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_);
}
@ -480,6 +482,18 @@ void MessageFieldGenerator::GenerateByteSize(io::Printer* printer) const {
" *$field_member$);\n");
}
void MessageFieldGenerator::GenerateIsInitialized(io::Printer* printer) const {
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
if (!has_required_fields_) return;
Formatter format(printer, variables_);
format(
"if (_internal_has_$name$()) {\n"
" if (!$name$_->IsInitialized()) return false;\n"
"}\n");
}
void MessageFieldGenerator::GenerateConstinitInitializer(
io::Printer* printer) const {
Formatter format(printer, variables_);
@ -641,6 +655,17 @@ void MessageOneofFieldGenerator::GenerateConstructorCode(
// space only when this field is used.
}
void MessageOneofFieldGenerator::GenerateIsInitialized(
io::Printer* printer) const {
if (!has_required_fields_) return;
Formatter format(printer, variables_);
format(
"if (_internal_has_$name$()) {\n"
" if (!$field_member$->IsInitialized()) return false;\n"
"}\n");
}
// ===================================================================
RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
@ -648,7 +673,9 @@ RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
MessageSCCAnalyzer* scc_analyzer)
: FieldGenerator(descriptor, options),
implicit_weak_field_(
IsImplicitWeakField(descriptor, options, scc_analyzer)) {
IsImplicitWeakField(descriptor, options, scc_analyzer)),
has_required_fields_(
scc_analyzer->HasRequiredFields(descriptor->message_type())) {
SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_);
}
@ -835,6 +862,24 @@ void RepeatedMessageFieldGenerator::GenerateByteSize(
"}\n");
}
void RepeatedMessageFieldGenerator::GenerateIsInitialized(
io::Printer* printer) const {
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
if (!has_required_fields_) return;
Formatter format(printer, variables_);
if (implicit_weak_field_) {
format(
"if (!::$proto_ns$::internal::AllAreInitializedWeak($name$_.weak))\n"
" return false;\n");
} else {
format(
"if (!::$proto_ns$::internal::AllAreInitialized($name$_))\n"
" return false;\n");
}
}
void RepeatedMessageFieldGenerator::GenerateConstinitInitializer(
io::Printer* printer) const {
Formatter format(printer, variables_);

View File

@ -50,7 +50,7 @@ class MessageFieldGenerator : public FieldGenerator {
MessageFieldGenerator(const FieldDescriptor* descriptor,
const Options& options,
MessageSCCAnalyzer* scc_analyzer);
~MessageFieldGenerator();
~MessageFieldGenerator() override;
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const override;
@ -71,10 +71,12 @@ class MessageFieldGenerator : public FieldGenerator {
void GenerateSerializeWithCachedSizesToArray(
io::Printer* printer) const override;
void GenerateByteSize(io::Printer* printer) const override;
void GenerateIsInitialized(io::Printer* printer) const override;
void GenerateConstinitInitializer(io::Printer* printer) const override;
protected:
const bool implicit_weak_field_;
const bool has_required_fields_;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
@ -85,7 +87,7 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator {
MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
const Options& options,
MessageSCCAnalyzer* scc_analyzer);
~MessageOneofFieldGenerator();
~MessageOneofFieldGenerator() override;
// implements FieldGenerator ---------------------------------------
void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
@ -99,6 +101,7 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator {
void GenerateSwappingCode(io::Printer* printer) const override;
void GenerateDestructorCode(io::Printer* printer) const override;
void GenerateConstructorCode(io::Printer* printer) const override;
void GenerateIsInitialized(io::Printer* printer) const override;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator);
@ -109,7 +112,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
const Options& options,
MessageSCCAnalyzer* scc_analyzer);
~RepeatedMessageFieldGenerator();
~RepeatedMessageFieldGenerator() override;
// implements FieldGenerator ---------------------------------------
void GeneratePrivateMembers(io::Printer* printer) const override;
@ -123,10 +126,12 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
void GenerateSerializeWithCachedSizesToArray(
io::Printer* printer) const override;
void GenerateByteSize(io::Printer* printer) const override;
void GenerateIsInitialized(io::Printer* printer) const override;
void GenerateConstinitInitializer(io::Printer* printer) const override;
private:
const bool implicit_weak_field_;
const bool has_required_fields_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
};

View File

@ -70,7 +70,7 @@ struct Options {
bool opensource_runtime = false;
bool annotate_accessor = false;
bool unused_field_stripping = false;
bool profile_driven_inline_string = false;
bool profile_driven_inline_string = true;
bool force_inline_string = false;
std::string runtime_include_base;
int num_cc_files = 0;

View File

@ -81,9 +81,9 @@ const char* TagType(const FieldDescriptor* field) {
return CodedTagType(TagSize(field->number()));
}
std::string TcParserBaseName(const Options& options) {
std::string TcParserName(const Options& options) {
return StrCat("::", ProtobufNamespace(options),
"::internal::TcParserBase::");
"::internal::TcParser::");
}
std::string MessageTcParseFunctionName(const FieldDescriptor* field,
@ -93,8 +93,8 @@ std::string MessageTcParseFunctionName(const FieldDescriptor* field,
// For files with `option optimize_for = CODE_SIZE`, or which derive from
// `ZeroFieldsBase`, we need to call the `_InternalParse` function, because
// there is no generated tailcall function. For tailcall parsing, this is
// done by helpers in TcParserBase.
return StrCat(TcParserBaseName(options),
// done by helpers in TcParser.
return StrCat(TcParserName(options),
(field->is_repeated() ? "Repeated" : "Singular"),
"ParseMessage<",
QualifiedClassName(field->message_type()), //
@ -108,8 +108,7 @@ std::string MessageTcParseFunctionName(const FieldDescriptor* field,
}
std::string FieldParseFunctionName(const FieldDescriptor* field,
const Options& options,
uint32_t table_size_log2);
const Options& options);
} // namespace
@ -209,14 +208,14 @@ TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor,
case FieldDescriptor::TYPE_SINT64:
case FieldDescriptor::TYPE_SINT32:
case FieldDescriptor::TYPE_BOOL:
name = FieldParseFunctionName(field, options, table_size_log2);
name = FieldParseFunctionName(field, options);
break;
case FieldDescriptor::TYPE_BYTES:
if (field->options().ctype() == FieldOptions::STRING &&
field->default_value_string().empty() &&
!IsStringInlined(field, options)) {
name = FieldParseFunctionName(field, options, table_size_log2);
name = FieldParseFunctionName(field, options);
}
break;
@ -365,9 +364,8 @@ void ParseFunctionGenerator::GenerateTailcallParseFunction(Formatter& format) {
"const char* $classname$::_InternalParse(\n"
" const char* ptr, ::$proto_ns$::internal::ParseContext* ctx) {\n"
"$annotate_deserialize$"
" ptr = ::$proto_ns$::internal::TcParser<$1$>::ParseLoop(\n"
" this, ptr, ctx, &_table_.header);\n",
tc_table_info_->table_size_log2);
" ptr = ::$proto_ns$::internal::TcParser::ParseLoop(\n"
" this, ptr, ctx, &_table_.header);\n");
format(
" return ptr;\n"
"}\n\n");
@ -426,9 +424,9 @@ void ParseFunctionGenerator::GenerateTailcallFieldParseFunctions(
"return table->fallback(PROTOBUF_TC_PARAM_PASS);\n"
" ptr += $1$;\n"
" hasbits |= (uint64_t{1} << data.hasbit_idx());\n"
" ::$proto_ns$::internal::TcParserBase::SyncHasbits"
" ::$proto_ns$::internal::TcParser::SyncHasbits"
"(msg, hasbits, table);\n"
" auto& field = ::$proto_ns$::internal::TcParserBase::"
" auto& field = ::$proto_ns$::internal::TcParser::"
"RefAt<$classtype$*>(msg, data.offset());\n"
" if (field == nullptr)\n"
" field = CreateMaybeMessage<$classtype$>(ctx->data().arena);\n"
@ -448,9 +446,9 @@ void ParseFunctionGenerator::GenerateTailcallFieldParseFunctions(
"return table->fallback(PROTOBUF_TC_PARAM_PASS);\n"
" }\n"
" ptr += $1$;\n"
" auto& field = ::$proto_ns$::internal::TcParserBase::RefAt<"
" auto& field = ::$proto_ns$::internal::TcParser::RefAt<"
"::$proto_ns$::RepeatedPtrField<$classname$>>(msg, data.offset());\n"
" ::$proto_ns$::internal::TcParserBase::SyncHasbits"
" ::$proto_ns$::internal::TcParser::SyncHasbits"
"(msg, hasbits, table);\n"
" ptr = ctx->ParseMessage(field.Add(), ptr);\n"
" return ptr;\n"
@ -471,7 +469,7 @@ void ParseFunctionGenerator::GenerateDataDecls(io::Printer* printer) {
format.Indent();
}
format(
"static const ::$proto_ns$::internal::TailCallParseTable<$1$>\n"
"static const ::$proto_ns$::internal::TcParseTable<$1$>\n"
" _table_;\n",
tc_table_info_->table_size_log2);
if (should_generate_guarded_tctable()) {
@ -546,7 +544,7 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) {
if (tc_table_info_->use_generated_fallback) {
fallback = ClassName(descriptor_) + "::Tct_ParseFallback";
} else {
fallback = TcParserBaseName(options_) + "GenericFallback";
fallback = TcParserName(options_) + "GenericFallback";
if (GetOptimizeFor(descriptor_->file(), options_) ==
FileOptions::LITE_RUNTIME) {
fallback += "Lite";
@ -561,33 +559,48 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) {
// the table is sufficient we can use a generic routine, that just handles
// unknown fields and potentially an extension range.
format(
"const ::$proto_ns$::internal::TailCallParseTable<$1$>\n"
"const ::$proto_ns$::internal::TcParseTable<$1$>\n"
" $classname$::_table_ = {\n",
tc_table_info_->table_size_log2);
format.Indent();
format("{\n");
format.Indent();
if (num_hasbits_ > 0 || IsMapEntryMessage(descriptor_)) {
format("PROTOBUF_FIELD_OFFSET($classname$, _has_bits_),\n");
} else {
format("0, // no _has_bits_\n");
{
auto table_scope = format.ScopedIndent();
format("{\n");
{
auto header_scope = format.ScopedIndent();
if (num_hasbits_ > 0 || IsMapEntryMessage(descriptor_)) {
format("PROTOBUF_FIELD_OFFSET($classname$, _has_bits_),\n");
} else {
format("0, // no _has_bits_\n");
}
if (descriptor_->extension_range_count() == 1) {
format(
"PROTOBUF_FIELD_OFFSET($classname$, _extensions_),\n"
"$1$, $2$, // extension_range_{low,high}\n",
descriptor_->extension_range(0)->start,
descriptor_->extension_range(0)->end);
} else {
format("0, 0, 0, // no _extensions_\n");
}
format(
"$1$, 0, $2$, // fast_idx_mask, reserved, num_fields\n"
"&$3$._instance,\n"
"$4$ // fallback\n",
(((1 << tc_table_info_->table_size_log2) - 1) << 3),
descriptor_->field_count(),
DefaultInstanceName(descriptor_, options_), fallback);
}
format("}, {\n");
{
auto fast_scope = format.ScopedIndent();
GenerateFastFieldEntries(format, fallback);
}
format("},\n"); // entries[]
}
if (descriptor_->extension_range_count() == 1) {
format(
"PROTOBUF_FIELD_OFFSET($classname$, _extensions_),\n"
"$1$, $2$, // extension_range_{low,high}\n",
descriptor_->extension_range(0)->start,
descriptor_->extension_range(0)->end);
} else {
format("0, 0, 0, // no _extensions_\n");
}
format(
"&$1$._instance,\n"
"$2$ // fallback\n",
DefaultInstanceName(descriptor_, options_), fallback);
format.Outdent();
format("}, {\n");
format.Indent();
format("};\n\n"); // _table_
}
void ParseFunctionGenerator::GenerateFastFieldEntries(
Formatter& format, const std::string& fallback) {
for (const auto& info : tc_table_info_->fast_path_fields) {
if (info.field != nullptr) {
PrintFieldComment(format, info.field);
@ -604,10 +617,6 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) {
}
format("},\n");
}
format.Outdent();
format("},\n"); // entries[]
format.Outdent();
format("};\n\n"); // _table_
}
void ParseFunctionGenerator::GenerateArenaString(Formatter& format,
@ -634,6 +643,8 @@ void ParseFunctionGenerator::GenerateArenaString(Formatter& format,
", ~0x$2$u",
inlined_string_index / 32,
strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8));
} else {
GOOGLE_DCHECK(field->default_value_string().empty());
}
format(
");\n"
@ -1094,8 +1105,7 @@ void ParseFunctionGenerator::GenerateFieldSwitch(
namespace {
std::string FieldParseFunctionName(const FieldDescriptor* field,
const Options& options,
uint32_t table_size_log2) {
const Options& options) {
ParseCardinality card = //
field->is_packed() ? ParseCardinality::kPacked
: field->is_repeated() ? ParseCardinality::kRepeated
@ -1165,8 +1175,8 @@ std::string FieldParseFunctionName(const FieldDescriptor* field,
return "";
}
return "::" + ProtobufNamespace(options) + "::internal::" +
GetTailCallFieldHandlerName(card, type_format, table_size_log2,
return "::" + ProtobufNamespace(options) + "::internal::TcParser::" +
GetTailCallFieldHandlerName(card, type_format,
TagSize(field->number()), options);
}
@ -1174,32 +1184,10 @@ std::string FieldParseFunctionName(const FieldDescriptor* field,
std::string GetTailCallFieldHandlerName(ParseCardinality card,
TypeFormat type_format,
int table_size_log2,
int tag_length_bytes,
const Options& options) {
std::string name;
switch (card) {
case ParseCardinality::kPacked:
case ParseCardinality::kRepeated:
name = "TcParserBase::";
break;
case ParseCardinality::kSingular:
case ParseCardinality::kOneof:
switch (type_format) {
case TypeFormat::kBytes:
case TypeFormat::kString:
case TypeFormat::kStringValidateOnly:
name = "TcParserBase::";
break;
default:
name = StrCat("TcParser<", table_size_log2, ">::");
break;
}
}
// The field implementation functions are prefixed by cardinality:
// `Singular` for optional or implicit fields.
// `Repeated` for non-packed repeated.
@ -1281,26 +1269,24 @@ std::string GetTailCallFieldHandlerName(ParseCardinality card,
case TypeFormat::kVar64:
case TypeFormat::kVar32:
case TypeFormat::kBool:
name.append(
StrCat(", ", TcParserBaseName(options), "kNoConversion"));
StrAppend(&name, ", ", TcParserName(options), "kNoConversion");
break;
case TypeFormat::kSInt64:
case TypeFormat::kSInt32:
name.append(StrCat(", ", TcParserBaseName(options), "kZigZag"));
StrAppend(&name, ", ", TcParserName(options), "kZigZag");
break;
case TypeFormat::kBytes:
name.append(StrCat(", ", TcParserBaseName(options), "kNoUtf8"));
StrAppend(&name, ", ", TcParserName(options), "kNoUtf8");
break;
case TypeFormat::kString:
name.append(StrCat(", ", TcParserBaseName(options), "kUtf8"));
StrAppend(&name, ", ", TcParserName(options), "kUtf8");
break;
case TypeFormat::kStringValidateOnly:
name.append(
StrCat(", ", TcParserBaseName(options), "kUtf8ValidateOnly"));
StrAppend(&name, ", ", TcParserName(options), "kUtf8ValidateOnly");
break;
default:

View File

@ -118,6 +118,7 @@ class ParseFunctionGenerator {
// Generates the tail-call table definition.
void GenerateTailCallTable(Formatter& format);
void GenerateFastFieldEntries(Formatter& format, const std::string& fallback);
// Generates parsing code for an `ArenaString` field.
void GenerateArenaString(Formatter& format, const FieldDescriptor* field);
@ -187,7 +188,6 @@ enum class TypeFormat {
// parse_function_inc_generator_main.
std::string GetTailCallFieldHandlerName(ParseCardinality card,
TypeFormat type_format,
int table_size_log2,
int tag_length_bytes,
const Options& options);

View File

@ -159,12 +159,25 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
(*variables)["set_has_field_bit_builder"] = "";
(*variables)["clear_has_field_bit_builder"] = "";
if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
(*variables)["is_field_present_message"] =
"!" + (*variables)["name"] + "_.isEmpty()";
} else {
(*variables)["is_field_present_message"] =
(*variables)["name"] + "_ != " + (*variables)["default"];
switch (descriptor->type()) {
case FieldDescriptor::TYPE_BYTES:
(*variables)["is_field_present_message"] =
"!" + (*variables)["name"] + "_.isEmpty()";
break;
case FieldDescriptor::TYPE_FLOAT:
(*variables)["is_field_present_message"] =
"java.lang.Float.floatToRawIntBits(" + (*variables)["name"] +
"_) != 0";
break;
case FieldDescriptor::TYPE_DOUBLE:
(*variables)["is_field_present_message"] =
"java.lang.Double.doubleToRawLongBits(" + (*variables)["name"] +
"_) != 0";
break;
default:
(*variables)["is_field_present_message"] =
(*variables)["name"] + "_ != " + (*variables)["default"];
break;
}
}

View File

@ -164,12 +164,25 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
(*variables)["set_has_field_bit_message"] = "";
(*variables)["clear_has_field_bit_message"] = "";
if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
(*variables)["is_field_present_message"] =
"!" + (*variables)["name"] + "_.isEmpty()";
} else {
(*variables)["is_field_present_message"] =
(*variables)["name"] + "_ != " + (*variables)["default"];
switch (descriptor->type()) {
case FieldDescriptor::TYPE_BYTES:
(*variables)["is_field_present_message"] =
"!" + (*variables)["name"] + "_.isEmpty()";
break;
case FieldDescriptor::TYPE_FLOAT:
(*variables)["is_field_present_message"] =
"java.lang.Float.floatToRawIntBits(" + (*variables)["name"] +
"_) != 0";
break;
case FieldDescriptor::TYPE_DOUBLE:
(*variables)["is_field_present_message"] =
"java.lang.Double.doubleToRawLongBits(" + (*variables)["name"] +
"_) != 0";
break;
default:
(*variables)["is_field_present_message"] =
(*variables)["name"] + "_ != " + (*variables)["default"];
break;
}
}

View File

@ -859,7 +859,8 @@ void CodeGeneratorRequest::CopyFrom(const CodeGeneratorRequest& from) {
}
bool CodeGeneratorRequest::IsInitialized() const {
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(proto_file_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(proto_file_))
return false;
return true;
}

View File

@ -6766,8 +6766,10 @@ void DescriptorBuilder::ValidateEnumValueOptions(
}
void DescriptorBuilder::ValidateExtensionRangeOptions(
const std::string& /*full_name*/, Descriptor::ExtensionRange* /*extension_range*/,
const DescriptorProto_ExtensionRange& /*proto*/) {
const std::string& full_name, Descriptor::ExtensionRange* extension_range,
const DescriptorProto_ExtensionRange& proto) {
(void)full_name; // Parameter is used by Google-internal code.
(void)extension_range; // Parameter is used by Google-internal code.
}
void DescriptorBuilder::ValidateServiceOptions(
@ -7838,7 +7840,8 @@ void DescriptorBuilder::OptionInterpreter::SetUInt64(
}
void DescriptorBuilder::LogUnusedDependency(const FileDescriptorProto& proto,
const FileDescriptor* /*result*/) {
const FileDescriptor* result) {
(void)result; // Parameter is used by Google-internal code.
if (!unused_dependency_.empty()) {
auto itr = pool_->unused_import_track_files_.find(proto.name());
@ -7860,7 +7863,8 @@ void DescriptorBuilder::LogUnusedDependency(const FileDescriptorProto& proto,
}
Symbol DescriptorPool::CrossLinkOnDemandHelper(StringPiece name,
bool /*expecting_enum*/) const {
bool expecting_enum) const {
(void)expecting_enum; // Parameter is used by Google-internal code.
auto lookup_name = std::string(name);
if (!lookup_name.empty() && lookup_name[0] == '.') {
lookup_name = lookup_name.substr(1);

View File

@ -1429,7 +1429,8 @@ void FileDescriptorSet::CopyFrom(const FileDescriptorSet& from) {
}
bool FileDescriptorSet::IsInitialized() const {
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(file_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(file_))
return false;
return true;
}
@ -2080,10 +2081,14 @@ void FileDescriptorProto::CopyFrom(const FileDescriptorProto& from) {
}
bool FileDescriptorProto::IsInitialized() const {
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(message_type_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(enum_type_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(service_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(extension_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(message_type_))
return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(enum_type_))
return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(service_))
return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(extension_))
return false;
if (_internal_has_options()) {
if (!options_->IsInitialized()) return false;
}
@ -3165,12 +3170,18 @@ void DescriptorProto::CopyFrom(const DescriptorProto& from) {
}
bool DescriptorProto::IsInitialized() const {
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(field_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(nested_type_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(enum_type_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(extension_range_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(extension_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(oneof_decl_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(field_))
return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(nested_type_))
return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(enum_type_))
return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(extension_range_))
return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(extension_))
return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(oneof_decl_))
return false;
if (_internal_has_options()) {
if (!options_->IsInitialized()) return false;
}
@ -3394,7 +3405,8 @@ bool ExtensionRangeOptions::IsInitialized() const {
return false;
}
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_))
return false;
return true;
}
@ -4947,7 +4959,8 @@ void EnumDescriptorProto::CopyFrom(const EnumDescriptorProto& from) {
}
bool EnumDescriptorProto::IsInitialized() const {
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(value_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(value_))
return false;
if (_internal_has_options()) {
if (!options_->IsInitialized()) return false;
}
@ -5570,7 +5583,8 @@ void ServiceDescriptorProto::CopyFrom(const ServiceDescriptorProto& from) {
}
bool ServiceDescriptorProto::IsInitialized() const {
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(method_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(method_))
return false;
if (_internal_has_options()) {
if (!options_->IsInitialized()) return false;
}
@ -7065,7 +7079,8 @@ bool FileOptions::IsInitialized() const {
return false;
}
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_))
return false;
return true;
}
@ -7459,7 +7474,8 @@ bool MessageOptions::IsInitialized() const {
return false;
}
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_))
return false;
return true;
}
@ -7866,7 +7882,8 @@ bool FieldOptions::IsInitialized() const {
return false;
}
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_))
return false;
return true;
}
@ -8079,7 +8096,8 @@ bool OneofOptions::IsInitialized() const {
return false;
}
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_))
return false;
return true;
}
@ -8360,7 +8378,8 @@ bool EnumOptions::IsInitialized() const {
return false;
}
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_))
return false;
return true;
}
@ -8609,7 +8628,8 @@ bool EnumValueOptions::IsInitialized() const {
return false;
}
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_))
return false;
return true;
}
@ -8853,7 +8873,8 @@ bool ServiceOptions::IsInitialized() const {
return false;
}
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_))
return false;
return true;
}
@ -9145,7 +9166,8 @@ bool MethodOptions::IsInitialized() const {
return false;
}
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_))
return false;
return true;
}
@ -9865,7 +9887,8 @@ void UninterpretedOption::CopyFrom(const UninterpretedOption& from) {
}
bool UninterpretedOption::IsInitialized() const {
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(name_)) return false;
if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(name_))
return false;
return true;
}

View File

@ -1976,10 +1976,12 @@ void ExtensionSet::GrowCapacity(size_t minimum_new_capacity) {
map_ = new_map;
}
#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
#if (__cplusplus < 201703) && \
(!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
// static
constexpr uint16_t ExtensionSet::kMaximumFlatCapacity;
#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900
// && _MSC_VER < 1912))
void ExtensionSet::Erase(int key) {
if (PROTOBUF_PREDICT_FALSE(is_large())) {

View File

@ -50,6 +50,7 @@
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/stubs/strutil.h>
@ -1613,7 +1614,8 @@ std::string Reflection::GetString(const Message& message,
const std::string& Reflection::GetStringReference(const Message& message,
const FieldDescriptor* field,
std::string* /*scratch*/) const {
std::string* scratch) const {
(void)scratch; // Parameter is used by Google-internal code.
USAGE_CHECK_ALL(GetStringReference, SINGULAR, STRING);
if (field->is_extension()) {
return GetExtensionSet(message).GetString(field->number(),
@ -1701,7 +1703,8 @@ std::string Reflection::GetRepeatedString(const Message& message,
const std::string& Reflection::GetRepeatedStringReference(
const Message& message, const FieldDescriptor* field, int index,
std::string* /*scratch*/) const {
std::string* scratch) const {
(void)scratch; // Parameter is used by Google-internal code.
USAGE_CHECK_ALL(GetRepeatedStringReference, REPEATED, STRING);
if (field->is_extension()) {
return GetExtensionSet(message).GetRepeatedString(field->number(), index);
@ -2239,8 +2242,9 @@ void Reflection::UnsafeArenaAddAllocatedMessage(Message* message,
void* Reflection::MutableRawRepeatedField(Message* message,
const FieldDescriptor* field,
FieldDescriptor::CppType cpptype,
int /*ctype*/,
int ctype,
const Descriptor* desc) const {
(void)ctype; // Parameter is used by Google-internal code.
USAGE_CHECK_REPEATED("MutableRawRepeatedField");
CheckInvalidAccess(schema_, field);
@ -2518,9 +2522,13 @@ bool Reflection::HasBit(const Message& message,
case FieldDescriptor::CPPTYPE_UINT64:
return GetRaw<uint64_t>(message, field) != 0;
case FieldDescriptor::CPPTYPE_FLOAT:
return GetRaw<float>(message, field) != 0.0;
static_assert(sizeof(uint32_t) == sizeof(float),
"Code assumes uint32_t and float are the same size.");
return GetRaw<uint32_t>(message, field) != 0;
case FieldDescriptor::CPPTYPE_DOUBLE:
return GetRaw<double>(message, field) != 0.0;
static_assert(sizeof(uint64_t) == sizeof(double),
"Code assumes uint64_t and double are the same size.");
return GetRaw<uint64_t>(message, field) != 0;
case FieldDescriptor::CPPTYPE_ENUM:
return GetRaw<int>(message, field) != 0;
case FieldDescriptor::CPPTYPE_MESSAGE:
@ -2658,7 +2666,8 @@ HANDLE_TYPE(bool, FieldDescriptor::CPPTYPE_BOOL, -1);
void* Reflection::MutableRawRepeatedString(Message* message,
const FieldDescriptor* field,
bool /*is_string*/) const {
bool is_string) const {
(void)is_string; // Parameter is used by Google-internal code.
return MutableRawRepeatedField(message, field,
FieldDescriptor::CPPTYPE_STRING,
FieldOptions::STRING, nullptr);

View File

@ -65,39 +65,42 @@ struct TcFieldData {
uint64_t data;
};
struct TailCallParseTableBase;
struct TcParseTableBase;
// TailCallParseFunc is the function pointer type used in the tailcall table.
typedef const char* (*TailCallParseFunc)(PROTOBUF_TC_PARAM_DECL);
#if defined(_MSC_VER) && !defined(_WIN64)
#pragma warning(push)
// TailCallParseTableBase is intentionally overaligned on 32 bit targets.
// TcParseTableBase is intentionally overaligned on 32 bit targets.
#pragma warning(disable : 4324)
#endif
// Base class for message-level table with info for the tail-call parser.
struct alignas(uint64_t) TailCallParseTableBase {
struct alignas(uint64_t) TcParseTableBase {
// Common attributes for message layout:
uint16_t has_bits_offset;
uint16_t extension_offset;
uint32_t extension_range_low;
uint32_t extension_range_high;
uint8_t fast_idx_mask;
uint8_t reserved;
uint16_t num_fields;
const MessageLite* default_instance;
// Handler for fields which are not handled by table dispatch.
TailCallParseFunc fallback;
// Table entry for fast-path tailcall dispatch handling.
struct FieldEntry {
struct FastFieldEntry {
// Target function for dispatch:
TailCallParseFunc target;
// Field data used during parse:
TcFieldData bits;
};
// There is always at least one table entry.
const FieldEntry* table() const {
return reinterpret_cast<const FieldEntry*>(this + 1);
const FastFieldEntry* fast_entry(size_t idx) const {
return reinterpret_cast<const FastFieldEntry*>(this + 1) + idx;
}
};
@ -105,12 +108,12 @@ struct alignas(uint64_t) TailCallParseTableBase {
#pragma warning(pop)
#endif
static_assert(sizeof(TailCallParseTableBase::FieldEntry) <= 16,
static_assert(sizeof(TcParseTableBase::FastFieldEntry) <= 16,
"Field entry is too big.");
template <size_t kTableSizeLog2>
struct TailCallParseTable {
TailCallParseTableBase header;
template <size_t kFastTableSizeLog2>
struct TcParseTable {
TcParseTableBase header;
// Entries for each field.
//
@ -118,15 +121,14 @@ struct TailCallParseTable {
// number is masked to fit inside the table. Note that the parsing logic
// generally calls `TailCallParseTableBase::table()` instead of accessing
// this field directly.
TailCallParseTableBase::FieldEntry entries[(1 << kTableSizeLog2)];
TcParseTableBase::FastFieldEntry entries[(1 << kFastTableSizeLog2)];
};
static_assert(std::is_standard_layout<TailCallParseTable<1>>::value,
"TailCallParseTable must be standard layout.");
static_assert(std::is_standard_layout<TcParseTable<1>>::value,
"TcParseTable must be standard layout.");
static_assert(offsetof(TailCallParseTable<1>, entries) ==
sizeof(TailCallParseTableBase),
"Table entries must be laid out after TailCallParseTableBase.");
static_assert(offsetof(TcParseTable<1>, entries) == sizeof(TcParseTableBase),
"Table entries must be laid out after TcParseTableBase.");
} // namespace internal
} // namespace protobuf

View File

@ -44,7 +44,7 @@ namespace google {
namespace protobuf {
namespace internal {
const char* TcParserBase::GenericFallback(PROTOBUF_TC_PARAM_DECL) {
const char* TcParser::GenericFallback(PROTOBUF_TC_PARAM_DECL) {
return GenericFallbackImpl<Message, UnknownFieldSet>(PROTOBUF_TC_PARAM_PASS);
}

View File

@ -69,28 +69,28 @@ namespace internal {
#define PROTOBUF_TC_PARSE_SINGULAR1(MESSAGE) MESSAGE::Tct_ParseS1
#else
#define PROTOBUF_TC_PARSE_SINGULAR1(MESSAGE) \
::google::protobuf::internal::TcParserBase::SingularParseMessage<MESSAGE, uint8_t>
::google::protobuf::internal::TcParser::SingularParseMessage<MESSAGE, uint8_t>
#endif // PROTOBUF_TC_STATIC_PARSE_SINGULAR1
#if PROTOBUF_TC_STATIC_PARSE_SINGULAR2
#define PROTOBUF_TC_PARSE_SINGULAR2(MESSAGE) MESSAGE::Tct_ParseS2
#else
#define PROTOBUF_TC_PARSE_SINGULAR2(MESSAGE) \
::google::protobuf::internal::TcParserBase::SingularParseMessage<MESSAGE, uint16_t>
::google::protobuf::internal::TcParser::SingularParseMessage<MESSAGE, uint16_t>
#endif // PROTOBUF_TC_STATIC_PARSE_SINGULAR2
#if PROTOBUF_TC_STATIC_PARSE_REPEATED1
#define PROTOBUF_TC_PARSE_REPEATED1(MESSAGE) MESSAGE::Tct_ParseR1
#else
#define PROTOBUF_TC_PARSE_REPEATED1(MESSAGE) \
::google::protobuf::internal::TcParserBase::RepeatedParseMessage<MESSAGE, uint8_t>
::google::protobuf::internal::TcParser::RepeatedParseMessage<MESSAGE, uint8_t>
#endif // PROTOBUF_TC_STATIC_PARSE_REPEATED1
#if PROTOBUF_TC_STATIC_PARSE_REPEATED2
#define PROTOBUF_TC_PARSE_REPEATED2(MESSAGE) MESSAGE::Tct_ParseR2
#else
#define PROTOBUF_TC_PARSE_REPEATED2(MESSAGE) \
::google::protobuf::internal::TcParserBase::RepeatedParseMessage<MESSAGE, uint16_t>
::google::protobuf::internal::TcParser::RepeatedParseMessage<MESSAGE, uint16_t>
#endif // PROTOBUF_TC_STATIC_PARSE_REPEATED2
#ifndef NDEBUG
@ -106,11 +106,52 @@ extern template void AlignFail<4>(uintptr_t);
extern template void AlignFail<8>(uintptr_t);
#endif
class TcParserBase {
// TcParser implements most of the parsing logic for tailcall tables.
class TcParser final {
public:
static const char* GenericFallback(PROTOBUF_TC_PARAM_DECL);
static const char* GenericFallbackLite(PROTOBUF_TC_PARAM_DECL);
// Dispatch to the designated parse function
inline PROTOBUF_ALWAYS_INLINE static const char* TagDispatch(
PROTOBUF_TC_PARAM_DECL) {
const auto coded_tag = UnalignedLoad<uint16_t>(ptr);
const size_t idx = coded_tag & table->fast_idx_mask;
PROTOBUF_ASSUME((idx & 7) == 0);
auto* fast_entry = table->fast_entry(idx >> 3);
data = fast_entry->bits;
data.data ^= coded_tag;
PROTOBUF_MUSTTAIL return fast_entry->target(PROTOBUF_TC_PARAM_PASS);
}
// We can only safely call from field to next field if the call is optimized
// to a proper tail call. Otherwise we blow through stack. Clang and gcc
// reliably do this optimization in opt mode, but do not perform this in debug
// mode. Luckily the structure of the algorithm is such that it's always
// possible to just return and use the enclosing parse loop as a trampoline.
static const char* ToTagDispatch(PROTOBUF_TC_PARAM_DECL) {
constexpr bool always_return = !PROTOBUF_TAILCALL;
if (always_return || !ctx->DataAvailable(ptr)) {
PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
}
PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_PASS);
}
static const char* ParseLoop(MessageLite* msg, const char* ptr,
ParseContext* ctx,
const TcParseTableBase* table) {
ScopedArenaSwap saved(msg, ctx);
const uint32_t has_bits_offset = table->has_bits_offset;
while (!ctx->Done(&ptr)) {
uint64_t hasbits = 0;
if (has_bits_offset) hasbits = RefAt<uint32_t>(msg, has_bits_offset);
ptr = TagDispatch(msg, ptr, ctx, table, hasbits, {});
if (ptr == nullptr) break;
if (ctx->LastTag() != 1) break; // Ended on terminating tag
}
return ptr;
}
template <typename FieldType, typename TagType>
PROTOBUF_NOINLINE static const char* SingularParseMessage(
PROTOBUF_TC_PARAM_DECL) {
@ -145,6 +186,8 @@ class TcParserBase {
return ptr;
}
template <typename LayoutType, typename TagType>
static const char* SingularFixed(PROTOBUF_TC_PARAM_DECL);
template <typename LayoutType, typename TagType>
static const char* RepeatedFixed(PROTOBUF_TC_PARAM_DECL);
template <typename LayoutType, typename TagType>
@ -152,6 +195,8 @@ class TcParserBase {
enum VarintDecode { kNoConversion = 0, kZigZag = 1 };
template <typename FieldType, typename TagType, VarintDecode zigzag>
static const char* SingularVarint(PROTOBUF_TC_PARAM_DECL);
template <typename FieldType, typename TagType, VarintDecode zigzag>
static const char* RepeatedVarint(PROTOBUF_TC_PARAM_DECL);
template <typename FieldType, typename TagType, VarintDecode zigzag>
static const char* PackedVarint(PROTOBUF_TC_PARAM_DECL);
@ -175,7 +220,7 @@ class TcParserBase {
}
static inline PROTOBUF_ALWAYS_INLINE void SyncHasbits(
MessageLite* msg, uint64_t hasbits, const TailCallParseTableBase* table) {
MessageLite* msg, uint64_t hasbits, const TcParseTableBase* table) {
const uint32_t has_bits_offset = table->has_bits_offset;
if (has_bits_offset) {
// Only the first 32 has-bits are updated. Nothing above those is stored,
@ -185,7 +230,7 @@ class TcParserBase {
}
protected:
static inline PROTOBUF_ALWAYS_INLINE const char* Return(
static inline PROTOBUF_ALWAYS_INLINE const char* ToParseLoop(
PROTOBUF_TC_PARAM_DECL) {
(void)data;
(void)ctx;
@ -245,59 +290,6 @@ class TcParserBase {
}
};
// TcParser implements most of the parsing logic for tailcall tables.
//
// This is templated on lg2(table size), since dispatching depends upon the size
// of the table. The template parameter avoids runtime overhead for computing
// the table entry index.
template <uint32_t kPowerOf2>
struct TcParser final : TcParserBase {
// Dispatch to the designated parse function
inline PROTOBUF_ALWAYS_INLINE static const char* TagDispatch(
PROTOBUF_TC_PARAM_DECL) {
const auto coded_tag = UnalignedLoad<uint16_t>(ptr);
constexpr size_t kIdxMask = ((1 << (kPowerOf2)) - 1);
const size_t idx = (coded_tag >> 3) & kIdxMask;
data = table->table()[idx].bits;
data.data ^= coded_tag;
PROTOBUF_MUSTTAIL return table->table()[idx].target(PROTOBUF_TC_PARAM_PASS);
}
// We can only safely call from field to next field if the call is optimized
// to a proper tail call. Otherwise we blow through stack. Clang and gcc
// reliably do this optimization in opt mode, but do not perform this in debug
// mode. Luckily the structure of the algorithm is such that it's always
// possible to just return and use the enclosing parse loop as a trampoline.
static const char* TailCall(PROTOBUF_TC_PARAM_DECL) {
constexpr bool always_return = !PROTOBUF_TAILCALL;
if (always_return || !ctx->DataAvailable(ptr)) {
PROTOBUF_MUSTTAIL return Return(PROTOBUF_TC_PARAM_PASS);
}
PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_PASS);
}
static const char* ParseLoop(MessageLite* msg, const char* ptr,
ParseContext* ctx,
const TailCallParseTableBase* table) {
ScopedArenaSwap saved(msg, ctx);
const uint32_t has_bits_offset = table->has_bits_offset;
while (!ctx->Done(&ptr)) {
uint64_t hasbits = 0;
if (has_bits_offset) hasbits = RefAt<uint32_t>(msg, has_bits_offset);
ptr = TagDispatch(msg, ptr, ctx, table, hasbits, {});
if (ptr == nullptr) break;
if (ctx->LastTag() != 1) break; // Ended on terminating tag
}
return ptr;
}
template <typename LayoutType, typename TagType>
static const char* SingularFixed(PROTOBUF_TC_PARAM_DECL);
template <typename FieldType, typename TagType, VarintDecode zigzag>
static const char* SingularVarint(PROTOBUF_TC_PARAM_DECL);
};
// Declare helper functions:
#include <google/protobuf/generated_message_tctable_impl.inc>

View File

@ -34,120 +34,59 @@
#else
#define PROTOBUF_TCT_EXTERN extern
#endif
PROTOBUF_TCT_EXTERN template const char *TcParser<1>::ParseLoop(::PROTOBUF_NAMESPACE_ID::MessageLite*, char const*, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext*, ::PROTOBUF_NAMESPACE_ID::internal::TailCallParseTableBase const*);
PROTOBUF_TCT_EXTERN template const char *TcParser<2>::ParseLoop(::PROTOBUF_NAMESPACE_ID::MessageLite*, char const*, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext*, ::PROTOBUF_NAMESPACE_ID::internal::TailCallParseTableBase const*);
PROTOBUF_TCT_EXTERN template const char *TcParser<3>::ParseLoop(::PROTOBUF_NAMESPACE_ID::MessageLite*, char const*, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext*, ::PROTOBUF_NAMESPACE_ID::internal::TailCallParseTableBase const*);
PROTOBUF_TCT_EXTERN template const char *TcParser<4>::ParseLoop(::PROTOBUF_NAMESPACE_ID::MessageLite*, char const*, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext*, ::PROTOBUF_NAMESPACE_ID::internal::TailCallParseTableBase const*);
PROTOBUF_TCT_EXTERN template const char *TcParser<5>::ParseLoop(::PROTOBUF_NAMESPACE_ID::MessageLite*, char const*, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext*, ::PROTOBUF_NAMESPACE_ID::internal::TailCallParseTableBase const*);
PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParserBase::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
#undef PROTOBUF_TCT_EXTERN
// clang-format on

View File

@ -50,7 +50,7 @@ template void AlignFail<4>(uintptr_t);
template void AlignFail<8>(uintptr_t);
#endif
const char* TcParserBase::GenericFallbackLite(PROTOBUF_TC_PARAM_DECL) {
const char* TcParser::GenericFallbackLite(PROTOBUF_TC_PARAM_DECL) {
return GenericFallbackImpl<MessageLite, std::string>(PROTOBUF_TC_PARAM_PASS);
}
@ -75,9 +75,8 @@ inline PROTOBUF_ALWAYS_INLINE void InvertPacked(TcFieldData& data) {
// Fixed fields
//////////////////////////////////////////////////////////////////////////////
template <uint32_t kPowerOf2>
template <typename LayoutType, typename TagType>
const char* TcParser<kPowerOf2>::SingularFixed(PROTOBUF_TC_PARAM_DECL) {
const char* TcParser::SingularFixed(PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
return table->fallback(PROTOBUF_TC_PARAM_PASS);
}
@ -85,12 +84,11 @@ const char* TcParser<kPowerOf2>::SingularFixed(PROTOBUF_TC_PARAM_DECL) {
hasbits |= (uint64_t{1} << data.hasbit_idx());
std::memcpy(Offset(msg, data.offset()), ptr, sizeof(LayoutType));
ptr += sizeof(LayoutType);
// TailCall syncs any pending hasbits:
PROTOBUF_MUSTTAIL return TailCall(PROTOBUF_TC_PARAM_PASS);
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
}
template <typename LayoutType, typename TagType>
const char* TcParserBase::RepeatedFixed(PROTOBUF_TC_PARAM_DECL) {
const char* TcParser::RepeatedFixed(PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
// Check if the field can be parsed as packed repeated:
constexpr WireFormatLite::WireType fallback_wt =
@ -117,11 +115,11 @@ const char* TcParserBase::RepeatedFixed(PROTOBUF_TC_PARAM_DECL) {
if (!ctx->DataAvailable(ptr)) break;
} while (UnalignedLoad<TagType>(ptr) == expected_tag);
field.AddNAlreadyReserved(idx - 1);
return Return(PROTOBUF_TC_PARAM_PASS);
return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
}
template <typename LayoutType, typename TagType>
const char* TcParserBase::PackedFixed(PROTOBUF_TC_PARAM_DECL) {
const char* TcParser::PackedFixed(PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
// Try parsing as non-packed repeated:
constexpr WireFormatLite::WireType fallback_wt =
@ -278,30 +276,28 @@ inline PROTOBUF_ALWAYS_INLINE const char* ParseVarint(const char* p,
}
}
template <typename FieldType, TcParserBase::VarintDecode =
TcParserBase::VarintDecode::kNoConversion>
template <typename FieldType,
TcParser::VarintDecode = TcParser::VarintDecode::kNoConversion>
FieldType ZigZagDecodeHelper(uint64_t value) {
return static_cast<FieldType>(value);
}
template <>
int32_t ZigZagDecodeHelper<int32_t, TcParserBase::VarintDecode::kZigZag>(
int32_t ZigZagDecodeHelper<int32_t, TcParser::VarintDecode::kZigZag>(
uint64_t value) {
return WireFormatLite::ZigZagDecode32(value);
}
template <>
int64_t ZigZagDecodeHelper<int64_t, TcParserBase::VarintDecode::kZigZag>(
int64_t ZigZagDecodeHelper<int64_t, TcParser::VarintDecode::kZigZag>(
uint64_t value) {
return WireFormatLite::ZigZagDecode64(value);
}
} // namespace
template <uint32_t kPowerOf2>
template <typename FieldType, typename TagType,
TcParserBase::VarintDecode zigzag>
const char* TcParser<kPowerOf2>::SingularVarint(PROTOBUF_TC_PARAM_DECL) {
template <typename FieldType, typename TagType, TcParser::VarintDecode zigzag>
const char* TcParser::SingularVarint(PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
return table->fallback(PROTOBUF_TC_PARAM_PASS);
}
@ -314,13 +310,11 @@ const char* TcParser<kPowerOf2>::SingularVarint(PROTOBUF_TC_PARAM_DECL) {
}
RefAt<FieldType>(msg, data.offset()) =
ZigZagDecodeHelper<FieldType, zigzag>(tmp);
PROTOBUF_MUSTTAIL return TailCall(PROTOBUF_TC_PARAM_PASS);
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
}
template <typename FieldType, typename TagType,
TcParserBase::VarintDecode zigzag>
PROTOBUF_NOINLINE const char* TcParserBase::RepeatedVarint(
PROTOBUF_TC_PARAM_DECL) {
template <typename FieldType, typename TagType, TcParser::VarintDecode zigzag>
PROTOBUF_NOINLINE const char* TcParser::RepeatedVarint(PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
// Try parsing as non-packed repeated:
InvertPacked<WireFormatLite::WIRETYPE_VARINT>(data);
@ -344,13 +338,11 @@ PROTOBUF_NOINLINE const char* TcParserBase::RepeatedVarint(
break;
}
} while (UnalignedLoad<TagType>(ptr) == expected_tag);
return Return(PROTOBUF_TC_PARAM_PASS);
return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
}
template <typename FieldType, typename TagType,
TcParserBase::VarintDecode zigzag>
PROTOBUF_NOINLINE const char* TcParserBase::PackedVarint(
PROTOBUF_TC_PARAM_DECL) {
template <typename FieldType, typename TagType, TcParser::VarintDecode zigzag>
PROTOBUF_NOINLINE const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
InvertPacked<WireFormatLite::WIRETYPE_VARINT>(data);
if (data.coded_tag<TagType>() == 0) {
@ -400,8 +392,8 @@ const char* SingularStringParserFallback(ArenaStringPtr* s, const char* ptr,
} // namespace
template <typename TagType, TcParserBase::Utf8Type utf8>
const char* TcParserBase::SingularString(PROTOBUF_TC_PARAM_DECL) {
template <typename TagType, TcParser::Utf8Type utf8>
const char* TcParser::SingularString(PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
return table->fallback(PROTOBUF_TC_PARAM_PASS);
}
@ -420,19 +412,19 @@ const char* TcParserBase::SingularString(PROTOBUF_TC_PARAM_DECL) {
#ifdef NDEBUG
case kUtf8ValidateOnly:
#endif
return Return(PROTOBUF_TC_PARAM_PASS);
return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
default:
if (PROTOBUF_PREDICT_TRUE(IsStructurallyValidUTF8(field.Get()))) {
return Return(PROTOBUF_TC_PARAM_PASS);
return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
}
PrintUTF8ErrorLog("unknown", "parsing", false);
return utf8 == kUtf8 ? Error(PROTOBUF_TC_PARAM_PASS)
: Return(PROTOBUF_TC_PARAM_PASS);
: ToParseLoop(PROTOBUF_TC_PARAM_PASS);
}
}
template <typename TagType, TcParserBase::Utf8Type utf8>
const char* TcParserBase::RepeatedString(PROTOBUF_TC_PARAM_DECL) {
template <typename TagType, TcParser::Utf8Type utf8>
const char* TcParser::RepeatedString(PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
return table->fallback(PROTOBUF_TC_PARAM_PASS);
}
@ -453,7 +445,7 @@ const char* TcParserBase::RepeatedString(PROTOBUF_TC_PARAM_DECL) {
}
if (!ctx->DataAvailable(ptr)) break;
} while (UnalignedLoad<TagType>(ptr) == expected_tag);
return Return(PROTOBUF_TC_PARAM_PASS);
return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
}
#define PROTOBUF_TCT_SOURCE

View File

@ -523,7 +523,8 @@ struct PackedFieldHelper {
template <>
struct PackedFieldHelper<WireFormatLite::TYPE_STRING> {
template <typename O>
static void Serialize(const void* /*field*/, const FieldMetadata& md, O* /*output*/) {
static void Serialize(const void* /*field*/, const FieldMetadata& md,
O* /*output*/) {
GOOGLE_LOG(FATAL) << "Not implemented field number " << md.tag << " with type "
<< md.type;
}

View File

@ -710,6 +710,9 @@ class PROTOBUF_EXPORT EpsCopyOutputStream {
// aliasing the buffer (ie. not copying the data). The caller is responsible
// to make sure the buffer is alive for the duration of the
// ZeroCopyOutputStream.
#ifndef NDEBUG
PROTOBUF_NOINLINE
#endif
uint8_t* WriteRawMaybeAliased(const void* data, int size, uint8_t* ptr) {
if (aliasing_enabled_) {
return WriteAliasedRaw(data, size, ptr);
@ -719,6 +722,9 @@ class PROTOBUF_EXPORT EpsCopyOutputStream {
}
#ifndef NDEBUG
PROTOBUF_NOINLINE
#endif
uint8_t* WriteStringMaybeAliased(uint32_t num, const std::string& s,
uint8_t* ptr) {
std::ptrdiff_t size = s.size();
@ -750,6 +756,9 @@ class PROTOBUF_EXPORT EpsCopyOutputStream {
return ptr + size;
}
template <typename T>
#ifndef NDEBUG
PROTOBUF_NOINLINE
#endif
uint8_t* WriteBytes(uint32_t num, const T& s, uint8_t* ptr) {
return WriteString(num, s, ptr);
}

View File

@ -118,9 +118,10 @@ inline StringPiece as_string_view(const void* data, int size) {
}
// Returns true of all required fields are present / have values.
inline bool CheckFieldPresence(const internal::ParseContext& /*ctx*/,
inline bool CheckFieldPresence(const internal::ParseContext& ctx,
const MessageLite& msg,
MessageLite::ParseFlags parse_flags) {
(void)ctx; // Parameter is used by Google-internal code.
if (PROTOBUF_PREDICT_FALSE((parse_flags & MessageLite::kMergePartial) != 0)) {
return true;
}

View File

@ -95,7 +95,7 @@ class ParseContext;
class ExtensionSet;
class LazyField;
class RepeatedPtrFieldBase;
class TcParserBase;
class TcParser;
class WireFormatLite;
class WeakFieldMap;
@ -482,7 +482,7 @@ class PROTOBUF_EXPORT MessageLite {
friend class internal::ExtensionSet;
friend class internal::LazyField;
friend class internal::SwapFieldHelper;
friend class internal::TcParserBase;
friend class internal::TcParser;
friend class internal::WeakFieldMap;
friend class internal::WireFormatLite;

View File

@ -39,6 +39,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <cmath>
#include <limits>
#include <google/protobuf/message.h>
@ -876,5 +877,21 @@ TEST(MESSAGE_TEST_NAME, CheckSerializationWhenInterleavedExtensions) {
EXPECT_EQ(5, out_message.GetExtension(UNITTEST::TestExtensionRangeSerialize::bar_five));
}
TEST(MESSAGE_TEST_NAME, PreservesFloatingPointNegative0) {
UNITTEST::TestAllTypes in_message;
in_message.set_optional_float(-0.0f);
in_message.set_optional_double(-0.0);
std::string serialized;
EXPECT_TRUE(in_message.SerializeToString(&serialized));
UNITTEST::TestAllTypes out_message;
EXPECT_TRUE(out_message.ParseFromString(serialized));
EXPECT_EQ(in_message.optional_float(), out_message.optional_float());
EXPECT_EQ(std::signbit(in_message.optional_float()),
std::signbit(out_message.optional_float()));
EXPECT_EQ(in_message.optional_double(), out_message.optional_double());
EXPECT_EQ(std::signbit(in_message.optional_double()),
std::signbit(out_message.optional_double()));
}
} // namespace protobuf
} // namespace google

View File

@ -579,7 +579,8 @@
// https://github.com/protocolbuffers/protobuf/issues/8310
// Does not work yet with Visual Studio 2019 Update 16.10
#define PROTOBUF_CONSTINIT constinit
#elif !defined(_MSC_VER) && __has_cpp_attribute(clang::require_constant_initialization)
#elif !defined(_MSC_VER) && \
__has_cpp_attribute(clang::require_constant_initialization)
#define PROTOBUF_CONSTINIT [[clang::require_constant_initialization]]
#else
#define PROTOBUF_CONSTINIT
@ -696,7 +697,7 @@
#define PROTOBUF_TC_PARAM_DECL \
::google::protobuf::MessageLite *msg, const char *ptr, \
::google::protobuf::internal::ParseContext *ctx, \
const ::google::protobuf::internal::TailCallParseTableBase *table, \
const ::google::protobuf::internal::TcParseTableBase *table, \
uint64_t hasbits, ::google::protobuf::internal::TcFieldData data
#ifdef PROTOBUF_UNUSED

View File

@ -61,7 +61,8 @@ class RandomAccessRepeatedFieldAccessor : public RepeatedFieldAccessor {
const Iterator* b) const override {
return a == b;
}
void DeleteIterator(const Field* /*data*/, Iterator* /*iterator*/) const override {}
void DeleteIterator(const Field* /*data*/,
Iterator* /*iterator*/) const override {}
const Value* GetIteratorValue(const Field* data, const Iterator* iterator,
Value* scratch_space) const override {
return Get(data, static_cast<int>(IteratorToPosition(iterator)),

View File

@ -38,119 +38,12 @@
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/implicit_weak_message.h>
#include <google/protobuf/port_def.inc>
namespace google {
namespace protobuf {
namespace internal {
void** RepeatedPtrFieldBase::InternalExtend(int extend_amount) {
int new_size = current_size_ + extend_amount;
if (total_size_ >= new_size) {
// N.B.: rep_ is non-nullptr because extend_amount is always > 0, hence
// total_size must be non-zero since it is lower-bounded by new_size.
return &rep_->elements[current_size_];
}
Rep* old_rep = rep_;
Arena* arena = GetArena();
new_size = std::max(internal::kRepeatedFieldLowerClampLimit,
std::max(total_size_ * 2, new_size));
GOOGLE_CHECK_LE(static_cast<int64_t>(new_size),
static_cast<int64_t>(
(std::numeric_limits<size_t>::max() - kRepHeaderSize) /
sizeof(old_rep->elements[0])))
<< "Requested size is too large to fit into size_t.";
size_t bytes = kRepHeaderSize + sizeof(old_rep->elements[0]) * new_size;
if (arena == nullptr) {
rep_ = reinterpret_cast<Rep*>(::operator new(bytes));
} else {
rep_ = reinterpret_cast<Rep*>(Arena::CreateArray<char>(arena, bytes));
}
#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
const int old_total_size = total_size_;
#endif
total_size_ = new_size;
if (old_rep && old_rep->allocated_size > 0) {
memcpy(rep_->elements, old_rep->elements,
old_rep->allocated_size * sizeof(rep_->elements[0]));
rep_->allocated_size = old_rep->allocated_size;
} else {
rep_->allocated_size = 0;
}
if (arena == nullptr) {
#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
const size_t old_size =
old_total_size * sizeof(rep_->elements[0]) + kRepHeaderSize;
::operator delete(static_cast<void*>(old_rep), old_size);
#else
::operator delete(static_cast<void*>(old_rep));
#endif
}
return &rep_->elements[current_size_];
}
void RepeatedPtrFieldBase::Reserve(int new_size) {
if (new_size > current_size_) {
InternalExtend(new_size - current_size_);
}
}
void RepeatedPtrFieldBase::DestroyProtos() {
GOOGLE_DCHECK(rep_);
GOOGLE_DCHECK(arena_ == nullptr);
int n = rep_->allocated_size;
void* const* elements = rep_->elements;
for (int i = 0; i < n; i++) {
delete static_cast<MessageLite*>(elements[i]);
}
#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
const size_t size = total_size_ * sizeof(elements[0]) + kRepHeaderSize;
::operator delete(static_cast<void*>(rep_), size);
rep_ = nullptr;
#else
::operator delete(static_cast<void*>(rep_));
rep_ = nullptr;
#endif
}
void* RepeatedPtrFieldBase::AddOutOfLineHelper(void* obj) {
if (!rep_ || rep_->allocated_size == total_size_) {
InternalExtend(1); // Equivalent to "Reserve(total_size_ + 1)"
}
++rep_->allocated_size;
rep_->elements[current_size_++] = obj;
return obj;
}
void RepeatedPtrFieldBase::CloseGap(int start, int num) {
if (rep_ == nullptr) return;
// Close up a gap of "num" elements starting at offset "start".
for (int i = start + num; i < rep_->allocated_size; ++i)
rep_->elements[i - num] = rep_->elements[i];
current_size_ -= num;
rep_->allocated_size -= num;
}
MessageLite* RepeatedPtrFieldBase::AddWeak(const MessageLite* prototype) {
if (rep_ != nullptr && current_size_ < rep_->allocated_size) {
return reinterpret_cast<MessageLite*>(rep_->elements[current_size_++]);
}
if (!rep_ || rep_->allocated_size == total_size_) {
Reserve(total_size_ + 1);
}
++rep_->allocated_size;
MessageLite* result = prototype
? prototype->New(arena_)
: Arena::CreateMessage<ImplicitWeakMessage>(arena_);
rep_->elements[current_size_++] = result;
return result;
}
} // namespace internal
template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<bool>;
template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField<int32_t>;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,157 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/repeated_field.h>
#include <algorithm>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/implicit_weak_message.h>
#include <google/protobuf/port_def.inc>
namespace google {
namespace protobuf {
namespace internal {
void** RepeatedPtrFieldBase::InternalExtend(int extend_amount) {
int new_size = current_size_ + extend_amount;
if (total_size_ >= new_size) {
// N.B.: rep_ is non-nullptr because extend_amount is always > 0, hence
// total_size must be non-zero since it is lower-bounded by new_size.
return &rep_->elements[current_size_];
}
Rep* old_rep = rep_;
Arena* arena = GetArena();
new_size = std::max(internal::kRepeatedFieldLowerClampLimit,
std::max(total_size_ * 2, new_size));
GOOGLE_CHECK_LE(static_cast<int64_t>(new_size),
static_cast<int64_t>(
(std::numeric_limits<size_t>::max() - kRepHeaderSize) /
sizeof(old_rep->elements[0])))
<< "Requested size is too large to fit into size_t.";
size_t bytes = kRepHeaderSize + sizeof(old_rep->elements[0]) * new_size;
if (arena == nullptr) {
rep_ = reinterpret_cast<Rep*>(::operator new(bytes));
} else {
rep_ = reinterpret_cast<Rep*>(Arena::CreateArray<char>(arena, bytes));
}
#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
const int old_total_size = total_size_;
#endif
total_size_ = new_size;
if (old_rep && old_rep->allocated_size > 0) {
memcpy(rep_->elements, old_rep->elements,
old_rep->allocated_size * sizeof(rep_->elements[0]));
rep_->allocated_size = old_rep->allocated_size;
} else {
rep_->allocated_size = 0;
}
if (arena == nullptr) {
#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
const size_t old_size =
old_total_size * sizeof(rep_->elements[0]) + kRepHeaderSize;
::operator delete(static_cast<void*>(old_rep), old_size);
#else
::operator delete(static_cast<void*>(old_rep));
#endif
}
return &rep_->elements[current_size_];
}
void RepeatedPtrFieldBase::Reserve(int new_size) {
if (new_size > current_size_) {
InternalExtend(new_size - current_size_);
}
}
void RepeatedPtrFieldBase::DestroyProtos() {
GOOGLE_DCHECK(rep_);
GOOGLE_DCHECK(arena_ == nullptr);
int n = rep_->allocated_size;
void* const* elements = rep_->elements;
for (int i = 0; i < n; i++) {
delete static_cast<MessageLite*>(elements[i]);
}
#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
const size_t size = total_size_ * sizeof(elements[0]) + kRepHeaderSize;
::operator delete(static_cast<void*>(rep_), size);
rep_ = nullptr;
#else
::operator delete(static_cast<void*>(rep_));
rep_ = nullptr;
#endif
}
void* RepeatedPtrFieldBase::AddOutOfLineHelper(void* obj) {
if (!rep_ || rep_->allocated_size == total_size_) {
InternalExtend(1); // Equivalent to "Reserve(total_size_ + 1)"
}
++rep_->allocated_size;
rep_->elements[current_size_++] = obj;
return obj;
}
void RepeatedPtrFieldBase::CloseGap(int start, int num) {
if (rep_ == nullptr) return;
// Close up a gap of "num" elements starting at offset "start".
for (int i = start + num; i < rep_->allocated_size; ++i)
rep_->elements[i - num] = rep_->elements[i];
current_size_ -= num;
rep_->allocated_size -= num;
}
MessageLite* RepeatedPtrFieldBase::AddWeak(const MessageLite* prototype) {
if (rep_ != nullptr && current_size_ < rep_->allocated_size) {
return reinterpret_cast<MessageLite*>(rep_->elements[current_size_++]);
}
if (!rep_ || rep_->allocated_size == total_size_) {
Reserve(total_size_ + 1);
}
++rep_->allocated_size;
MessageLite* result = prototype
? prototype->New(arena_)
: Arena::CreateMessage<ImplicitWeakMessage>(arena_);
rep_->elements[current_size_++] = result;
return result;
}
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>

File diff suppressed because it is too large Load Diff

View File

@ -194,6 +194,22 @@ message TestAllTypesProto2 {
optional uint32 group_uint32 = 203;
}
// default values
optional int32 default_int32 = 241 [ default = -123456789];
optional int64 default_int64 = 242 [ default = -9123456789123456789];
optional uint32 default_uint32 = 243 [ default = 2123456789];
optional uint64 default_uint64 = 244 [ default = 10123456789123456789];
optional sint32 default_sint32 = 245 [ default = -123456789];
optional sint64 default_sint64 = 246 [default = -9123456789123456789];
optional fixed32 default_fixed32 = 247 [ default = 2123456789];
optional fixed64 default_fixed64 = 248 [ default = 10123456789123456789];
optional sfixed32 default_sfixed32 = 249 [ default = -123456789];
optional sfixed64 default_sfixed64 = 250 [default = -9123456789123456789];
optional float default_float = 251 [ default = 9e9];
optional double default_double = 252 [ default = 7e22];
optional bool default_bool = 253 [ default = true];
optional string default_string = 254 [ default = "Rosebud"];
// Test field-name-to-JSON-name convention.
// (protobuf says names can be any valid C/C++ identifier.)
optional int32 fieldname1 = 401;

View File

@ -426,14 +426,19 @@ class TextFormat::Parser::ParserImpl {
TryConsume("[")) {
std::string full_type_name, prefix;
DO(ConsumeAnyTypeUrl(&full_type_name, &prefix));
DO(Consume("]"));
TryConsume(":"); // ':' is optional between message labels and values.
std::string prefix_and_full_type_name =
StrCat(prefix, full_type_name);
DO(ConsumeBeforeWhitespace("]"));
TryConsumeWhitespace(prefix_and_full_type_name, "Any");
// ':' is optional between message labels and values.
TryConsumeBeforeWhitespace(":");
TryConsumeWhitespace(prefix_and_full_type_name, "Any");
std::string serialized_value;
const Descriptor* value_descriptor =
finder_ ? finder_->FindAnyType(*message, prefix, full_type_name)
: DefaultFinderFindAnyType(*message, prefix, full_type_name);
if (value_descriptor == nullptr) {
ReportError("Could not find type \"" + prefix + full_type_name +
ReportError("Could not find type \"" + prefix_and_full_type_name +
"\" stored in google.protobuf.Any.");
return false;
}
@ -449,14 +454,15 @@ class TextFormat::Parser::ParserImpl {
}
}
reflection->SetString(message, any_type_url_field,
std::string(prefix + full_type_name));
prefix_and_full_type_name);
reflection->SetString(message, any_value_field, serialized_value);
return true;
}
if (TryConsume("[")) {
// Extension.
DO(ConsumeFullTypeName(&field_name));
DO(Consume("]"));
DO(ConsumeBeforeWhitespace("]"));
TryConsumeWhitespace(message->GetTypeName(), "Extension");
field = finder_ ? finder_->FindExtension(message, field_name)
: DefaultFinderFindExtension(message, field_name);
@ -475,7 +481,8 @@ class TextFormat::Parser::ParserImpl {
}
}
} else {
DO(ConsumeIdentifier(&field_name));
DO(ConsumeIdentifierBeforeWhitespace(&field_name));
TryConsumeWhitespace(message->GetTypeName(), "Normal");
int32_t field_number;
if (allow_field_number_ && safe_strto32(field_name, &field_number)) {
@ -543,11 +550,13 @@ class TextFormat::Parser::ParserImpl {
// start with "{" or "<" which indicates the beginning of a message body.
// If there is no ":" or there is a "{" or "<" after ":", this field has
// to be a message or the input is ill-formed.
if (TryConsume(":") && !LookingAt("{") && !LookingAt("<")) {
return SkipFieldValue();
} else {
return SkipFieldMessage();
if (TryConsumeBeforeWhitespace(":")) {
TryConsumeWhitespace(message->GetTypeName(), "Unknown/Reserved");
if (!LookingAt("{") && !LookingAt("<")) {
return SkipFieldValue();
}
}
return SkipFieldMessage();
}
if (singular_overwrite_policy_ == FORBID_SINGULAR_OVERWRITES) {
@ -577,7 +586,8 @@ class TextFormat::Parser::ParserImpl {
// Perform special handling for embedded message types.
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
// ':' is optional here.
bool consumed_semicolon = TryConsume(":");
bool consumed_semicolon = TryConsumeBeforeWhitespace(":");
TryConsumeWhitespace(message->GetTypeName(), "Normal");
if (consumed_semicolon && field->options().weak() &&
LookingAtType(io::Tokenizer::TYPE_STRING)) {
// we are getting a bytes string for a weak field.
@ -591,7 +601,8 @@ class TextFormat::Parser::ParserImpl {
}
} else {
// ':' is required here.
DO(Consume(":"));
DO(ConsumeBeforeWhitespace(":"));
TryConsumeWhitespace(message->GetTypeName(), "Normal");
}
if (field->is_repeated() && TryConsume("[")) {
@ -645,11 +656,12 @@ class TextFormat::Parser::ParserImpl {
if (TryConsume("[")) {
// Extension name or type URL.
DO(ConsumeTypeUrlOrFullTypeName());
DO(Consume("]"));
DO(ConsumeBeforeWhitespace("]"));
} else {
std::string field_name;
DO(ConsumeIdentifier(&field_name));
DO(ConsumeIdentifierBeforeWhitespace(&field_name));
}
TryConsumeWhitespace("Unknown/Reserved", "n/a");
// Try to guess the type of this field.
// If this field is not a message, there should be a ":" between the
@ -657,8 +669,13 @@ class TextFormat::Parser::ParserImpl {
// start with "{" or "<" which indicates the beginning of a message body.
// If there is no ":" or there is a "{" or "<" after ":", this field has
// to be a message or the input is ill-formed.
if (TryConsume(":") && !LookingAt("{") && !LookingAt("<")) {
DO(SkipFieldValue());
if (TryConsumeBeforeWhitespace(":")) {
TryConsumeWhitespace("Unknown/Reserved", "n/a");
if (!LookingAt("{") && !LookingAt("<")) {
DO(SkipFieldValue());
} else {
DO(SkipFieldMessage());
}
} else {
DO(SkipFieldMessage());
}
@ -980,6 +997,15 @@ class TextFormat::Parser::ParserImpl {
return false;
}
// Similar to `ConsumeIdentifier`, but any following whitespace token may
// be reported.
bool ConsumeIdentifierBeforeWhitespace(std::string* identifier) {
tokenizer_.set_report_whitespace(true);
bool result = ConsumeIdentifier(identifier);
tokenizer_.set_report_whitespace(false);
return result;
}
// Consume a string of form "<id1>.<id2>....<idN>".
bool ConsumeFullTypeName(std::string* name) {
DO(ConsumeIdentifier(name));
@ -1207,6 +1233,16 @@ class TextFormat::Parser::ParserImpl {
return true;
}
// Similar to `Consume`, but the following token may be tokenized as
// TYPE_WHITESPACE.
bool ConsumeBeforeWhitespace(const std::string& value) {
// Report whitespace after this token, but only once.
tokenizer_.set_report_whitespace(true);
bool result = Consume(value);
tokenizer_.set_report_whitespace(false);
return result;
}
// Attempts to consume the supplied value. Returns false if a the
// token found does not match the value specified.
bool TryConsume(const std::string& value) {
@ -1218,6 +1254,26 @@ class TextFormat::Parser::ParserImpl {
}
}
// Similar to `TryConsume`, but the following token may be tokenized as
// TYPE_WHITESPACE.
bool TryConsumeBeforeWhitespace(const std::string& value) {
// Report whitespace after this token, but only once.
tokenizer_.set_report_whitespace(true);
bool result = TryConsume(value);
tokenizer_.set_report_whitespace(false);
return result;
}
bool TryConsumeWhitespace(const std::string& message_type,
const char* field_type) {
if (LookingAtType(io::Tokenizer::TYPE_WHITESPACE)) {
tokenizer_.Next();
return true;
}
return false;
}
// An internal instance of the Tokenizer's error collector, used to
// collect any base-level parse errors and feed them to the ParserImpl.
class ParserErrorCollector : public io::ErrorCollector {
@ -1768,7 +1824,8 @@ void TextFormat::FastFieldValuePrinter::PrintDouble(
generator->PrintString(!std::isnan(val) ? SimpleDtoa(val) : "nan");
}
void TextFormat::FastFieldValuePrinter::PrintEnum(
int32_t /*val*/, const std::string& name, BaseTextGenerator* generator) const {
int32_t /*val*/, const std::string& name,
BaseTextGenerator* generator) const {
generator->PrintString(name);
}
@ -1879,8 +1936,8 @@ class FieldValuePrinterWrapper : public TextFormat::FastFieldValuePrinter {
TextFormat::BaseTextGenerator* generator) const override {
generator->PrintString(delegate_->PrintEnum(val, name));
}
void PrintFieldName(const Message& message, int /*field_index*/, int /*field_count*/,
const Reflection* reflection,
void PrintFieldName(const Message& message, int /*field_index*/,
int /*field_count*/, const Reflection* reflection,
const FieldDescriptor* field,
TextFormat::BaseTextGenerator* generator) const override {
generator->PrintString(

View File

@ -1965,6 +1965,102 @@ TEST_F(TextFormatParserTest, SetRecursionLimitUnknownFieldMessage) {
ExpectSuccessAndTree(input, &message, nullptr);
}
TEST_F(TextFormatParserTest, ParseAnyFieldWithAdditionalWhiteSpaces) {
Any any;
std::string parse_string =
"[type.googleapis.com/protobuf_unittest.TestAllTypes] \t : \t {\n"
" optional_int32: 321\n"
" optional_string: \"teststr0\"\n"
"}\n";
ASSERT_TRUE(TextFormat::ParseFromString(parse_string, &any));
TextFormat::Printer printer;
printer.SetExpandAny(true);
std::string text;
ASSERT_TRUE(printer.PrintToString(any, &text));
EXPECT_EQ(text,
"[type.googleapis.com/protobuf_unittest.TestAllTypes] {\n"
" optional_int32: 321\n"
" optional_string: \"teststr0\"\n"
"}\n");
}
TEST_F(TextFormatParserTest, ParseExtensionFieldWithAdditionalWhiteSpaces) {
unittest::TestAllExtensions proto;
std::string parse_string =
"[protobuf_unittest.optional_int32_extension] : \t 101\n"
"[protobuf_unittest.optional_int64_extension] \t : 102\n";
ASSERT_TRUE(TextFormat::ParseFromString(parse_string, &proto));
TextFormat::Printer printer;
std::string text;
ASSERT_TRUE(printer.PrintToString(proto, &text));
EXPECT_EQ(text,
"[protobuf_unittest.optional_int32_extension]: 101\n"
"[protobuf_unittest.optional_int64_extension]: 102\n");
}
TEST_F(TextFormatParserTest, ParseNormalFieldWithAdditionalWhiteSpaces) {
unittest::TestAllTypes proto;
std::string parse_string =
"repeated_int32 : \t 1\n"
"repeated_int32: 2\n"
"repeated_nested_message: {\n"
" bb: 3\n"
"}\n"
"repeated_nested_message : \t {\n"
" bb: 4\n"
"}\n"
"repeated_nested_message {\n"
" bb: 5\n"
"}\n";
ASSERT_TRUE(TextFormat::ParseFromString(parse_string, &proto));
TextFormat::Printer printer;
std::string text;
ASSERT_TRUE(printer.PrintToString(proto, &text));
EXPECT_EQ(text,
"repeated_int32: 1\n"
"repeated_int32: 2\n"
"repeated_nested_message {\n"
" bb: 3\n"
"}\n"
"repeated_nested_message {\n"
" bb: 4\n"
"}\n"
"repeated_nested_message {\n"
" bb: 5\n"
"}\n");
}
TEST_F(TextFormatParserTest, ParseSkippedFieldWithAdditionalWhiteSpaces) {
protobuf_unittest::TestAllTypes proto;
TextFormat::Parser parser;
parser.AllowUnknownField(true);
EXPECT_TRUE(
parser.ParseFromString("optional_int32: 321\n"
"unknown_field1 : \t 12345\n"
"[somewhere.unknown_extension1] {\n"
" unknown_field2 \t : 12345\n"
"}\n"
"[somewhere.unknown_extension2] : \t {\n"
" unknown_field3 \t : 12345\n"
" [somewhere.unknown_extension3] \t : {\n"
" unknown_field4: 10\n"
" }\n"
" [somewhere.unknown_extension4] \t {\n"
" }\n"
"}\n",
&proto));
std::string text;
TextFormat::Printer printer;
ASSERT_TRUE(printer.PrintToString(proto, &text));
EXPECT_EQ(text, "optional_int32: 321\n");
}
class TextFormatMessageSetTest : public testing::Test {
protected:
static const char proto_debug_string_[];
@ -2279,6 +2375,24 @@ TEST_F(TextFormatSilentMarkerTest, MapFieldAsFirstField) {
}
TEST(TextFormatFloatingPointTest, PreservesNegative0) {
proto3_unittest::TestAllTypes in_message;
in_message.set_optional_float(-0.0f);
in_message.set_optional_double(-0.0);
TextFormat::Printer printer;
std::string serialized;
EXPECT_TRUE(printer.PrintToString(in_message, &serialized));
proto3_unittest::TestAllTypes out_message;
TextFormat::Parser parser;
EXPECT_TRUE(parser.ParseFromString(serialized, &out_message));
EXPECT_EQ(in_message.optional_float(), out_message.optional_float());
EXPECT_EQ(std::signbit(in_message.optional_float()),
std::signbit(out_message.optional_float()));
EXPECT_EQ(in_message.optional_double(), out_message.optional_double());
EXPECT_EQ(std::signbit(in_message.optional_double()),
std::signbit(out_message.optional_double()));
}
} // namespace text_format_unittest
} // namespace protobuf
} // namespace google

View File

@ -251,7 +251,8 @@ void UnknownField::Delete() {
}
}
void UnknownField::DeepCopy(const UnknownField& /*other*/) {
void UnknownField::DeepCopy(const UnknownField& other) {
(void)other; // Parameter is used by Google-internal code.
switch (type()) {
case UnknownField::TYPE_LENGTH_DELIMITED:
data_.length_delimited_.string_value =

View File

@ -84,15 +84,15 @@ class PROTOBUF_EXPORT NoopErrorListener : public ErrorListener {
~NoopErrorListener() override {}
void InvalidName(const LocationTrackerInterface& /*loc*/,
StringPiece /*invalid_name*/,
StringPiece /*message*/) override {}
StringPiece /* invalid_name */,
StringPiece /* message */) override {}
void InvalidValue(const LocationTrackerInterface& /*loc*/,
StringPiece /*type_name*/,
StringPiece /*value*/) override {}
StringPiece /* type_name */,
StringPiece /* value */) override {}
void MissingField(const LocationTrackerInterface& /*loc*/,
StringPiece /*missing_name*/) override {}
void MissingField(const LocationTrackerInterface& /* loc */,
StringPiece /* missing_name */) override {}
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(NoopErrorListener);

View File

@ -863,7 +863,8 @@ bool JsonStreamParser::IsEmptyNullAllowed(TokenType type) {
}
util::Status JsonStreamParser::ReportFailure(StringPiece message,
ParseErrorType /*parse_code*/) {
ParseErrorType parse_code) {
(void)parse_code; // Parameter is used in Google-internal code.
static const int kContextLength = 20;
const char* p_start = p_.data();
const char* json_start = json_.data();

View File

@ -252,7 +252,7 @@ util::StatusOr<uint32_t> ProtoStreamObjectSource::RenderList(
}
util::StatusOr<uint32_t> ProtoStreamObjectSource::RenderMap(
const google::protobuf::Field* field, StringPiece /*name*/,
const google::protobuf::Field* field, StringPiece /* name */,
uint32_t list_tag, ObjectWriter* ow) const {
const google::protobuf::Type* field_type =
typeinfo_->GetTypeByTypeUrl(field->type_url());

View File

@ -78,25 +78,28 @@ class NumDiffsReporter : public google::protobuf::util::MessageDifferencer::Repo
// Report that a field has been added into Message2.
void ReportAdded(
const google::protobuf::Message& /*message1*/, const google::protobuf::Message& /*message2*/,
const google::protobuf::Message& /* message1 */,
const google::protobuf::Message& /* message2 */,
const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
/*field_path*/) override {
/*field_path*/) override {
++num_diffs_;
}
// Report that a field has been deleted from Message1.
void ReportDeleted(
const google::protobuf::Message& /*message1*/, const google::protobuf::Message& /*message2*/,
const google::protobuf::Message& /* message1 */,
const google::protobuf::Message& /* message2 */,
const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
/*field_path*/) override {
/*field_path*/) override {
++num_diffs_;
}
// Report that the value of a field has been modified.
void ReportModified(
const google::protobuf::Message& /*message1*/, const google::protobuf::Message& /*message2*/,
const google::protobuf::Message& /* message1 */,
const google::protobuf::Message& /* message2 */,
const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
/*field_path*/) override {
/*field_path*/) override {
++num_diffs_;
}

View File

@ -212,20 +212,6 @@ class PROTOBUF_EXPORT MessageDifferencer {
int unknown_field_index2 = -1;
};
// Class for processing Any deserialization. This logic is used by both the
// MessageDifferencer and StreamReporter classes.
class UnpackAnyField {
private:
std::unique_ptr<DynamicMessageFactory> dynamic_message_factory_;
public:
UnpackAnyField() = default;
~UnpackAnyField() = default;
// If "any" is of type google.protobuf.Any, extract its payload using
// DynamicMessageFactory and store in "data".
bool UnpackAny(const Message& any, std::unique_ptr<Message>* data);
};
// Abstract base class from which all MessageDifferencer
// reporters derive. The five Report* methods below will be called when
// a field has been added, deleted, modified, moved, or matched. The third
@ -628,6 +614,22 @@ class PROTOBUF_EXPORT MessageDifferencer {
// differences to any previously set reporters or output strings.
void ReportDifferencesTo(Reporter* reporter);
private:
// Class for processing Any deserialization. This logic is used by both the
// MessageDifferencer and StreamReporter classes.
class UnpackAnyField {
private:
std::unique_ptr<DynamicMessageFactory> dynamic_message_factory_;
public:
UnpackAnyField() = default;
~UnpackAnyField() = default;
// If "any" is of type google.protobuf.Any, extract its payload using
// DynamicMessageFactory and store in "data".
bool UnpackAny(const Message& any, std::unique_ptr<Message>* data);
};
public:
// An implementation of the MessageDifferencer Reporter that outputs
// any differences found in human-readable form to the supplied
// ZeroCopyOutputStream or Printer. If a printer is used, the delimiter

View File

@ -571,8 +571,9 @@ bool WireFormatLite::ReadBytes(io::CodedInputStream* input, std::string** p) {
}
void PrintUTF8ErrorLog(const char* field_name, const char* operation_str,
bool /*emit_stacktrace*/) {
bool emit_stacktrace) {
std::string stacktrace;
(void)emit_stacktrace; // Parameter is used by Google-internal code.
std::string quoted_field_name = "";
if (field_name != nullptr) {
quoted_field_name = StringPrintf(" '%s'", field_name);

View File

@ -349,7 +349,11 @@ uint8_t* DoubleValue::_InternalSerialize(
(void) cached_has_bits;
// double value = 1;
if (!(this->_internal_value() <= 0 && this->_internal_value() >= 0)) {
static_assert(sizeof(uint64_t) == sizeof(double), "Code assumes uint64_t and double are the same size.");
double tmp_value = this->_internal_value();
uint64_t raw_value;
memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
if (raw_value != 0) {
target = stream->EnsureSpace(target);
target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteDoubleToArray(1, this->_internal_value(), target);
}
@ -371,7 +375,11 @@ size_t DoubleValue::ByteSizeLong() const {
(void) cached_has_bits;
// double value = 1;
if (!(this->_internal_value() <= 0 && this->_internal_value() >= 0)) {
static_assert(sizeof(uint64_t) == sizeof(double), "Code assumes uint64_t and double are the same size.");
double tmp_value = this->_internal_value();
uint64_t raw_value;
memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
if (raw_value != 0) {
total_size += 1 + 8;
}
@ -397,7 +405,11 @@ void DoubleValue::MergeFrom(const DoubleValue& from) {
uint32_t cached_has_bits = 0;
(void) cached_has_bits;
if (!(from._internal_value() <= 0 && from._internal_value() >= 0)) {
static_assert(sizeof(uint64_t) == sizeof(double), "Code assumes uint64_t and double are the same size.");
double tmp_value = from._internal_value();
uint64_t raw_value;
memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
if (raw_value != 0) {
_internal_set_value(from._internal_value());
}
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
@ -527,7 +539,11 @@ uint8_t* FloatValue::_InternalSerialize(
(void) cached_has_bits;
// float value = 1;
if (!(this->_internal_value() <= 0 && this->_internal_value() >= 0)) {
static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size.");
float tmp_value = this->_internal_value();
uint32_t raw_value;
memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
if (raw_value != 0) {
target = stream->EnsureSpace(target);
target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteFloatToArray(1, this->_internal_value(), target);
}
@ -549,7 +565,11 @@ size_t FloatValue::ByteSizeLong() const {
(void) cached_has_bits;
// float value = 1;
if (!(this->_internal_value() <= 0 && this->_internal_value() >= 0)) {
static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size.");
float tmp_value = this->_internal_value();
uint32_t raw_value;
memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
if (raw_value != 0) {
total_size += 1 + 4;
}
@ -575,7 +595,11 @@ void FloatValue::MergeFrom(const FloatValue& from) {
uint32_t cached_has_bits = 0;
(void) cached_has_bits;
if (!(from._internal_value() <= 0 && from._internal_value() >= 0)) {
static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size.");
float tmp_value = from._internal_value();
uint32_t raw_value;
memcpy(&raw_value, &tmp_value, sizeof(tmp_value));
if (raw_value != 0) {
_internal_set_value(from._internal_value());
}
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);