Merge pull request #9090 from acozzette/sync-stage
Integrate from Piper for C++, Java, and Python
This commit is contained in:
commit
3e1967e10b
1
BUILD
1
BUILD
@ -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",
|
||||
|
15
CHANGES.txt
15
CHANGES.txt
@ -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)
|
||||
|
||||
|
14
WORKSPACE
14
WORKSPACE
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -255,7 +255,6 @@ junit_tests(
|
||||
":java_test_protos_java_proto",
|
||||
":test_util",
|
||||
"//external:easymock",
|
||||
"//external:easymock_classextension",
|
||||
"//external:guava",
|
||||
"//external:junit",
|
||||
"//external:truth",
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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("");
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -316,7 +316,6 @@ public class ServiceTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean matches(Object actual) {
|
||||
if (!(actual instanceof RpcCallback)) {
|
||||
return false;
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -14,6 +14,7 @@ java_library(
|
||||
"//external:error_prone_annotations",
|
||||
"//external:j2objc_annotations",
|
||||
"//external:gson",
|
||||
"//external:jsr305",
|
||||
"//external:guava",
|
||||
"//java/core",
|
||||
"//java/lite",
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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}");
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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": [],
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
)
|
||||
|
@ -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 \
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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_);
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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_);
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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())) {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)),
|
||||
|
@ -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
157
src/google/protobuf/repeated_ptr_field.cc
Normal file
157
src/google/protobuf/repeated_ptr_field.cc
Normal 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>
|
2014
src/google/protobuf/repeated_ptr_field.h
Normal file
2014
src/google/protobuf/repeated_ptr_field.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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 =
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
|
@ -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_;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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_);
|
||||
|
Loading…
Reference in New Issue
Block a user