Down integrate to GitHub

This commit is contained in:
Hao Nguyen 2019-05-03 14:33:43 -07:00
parent fbe4ccccc5
commit 1d4e959374
25 changed files with 655 additions and 287 deletions

View File

@ -2,6 +2,7 @@ set(libprotobuf_lite_files
${protobuf_source_dir}/src/google/protobuf/any_lite.cc
${protobuf_source_dir}/src/google/protobuf/arena.cc
${protobuf_source_dir}/src/google/protobuf/extension_set.cc
${protobuf_source_dir}/src/google/protobuf/generated_enum_util.cc
${protobuf_source_dir}/src/google/protobuf/generated_message_table_driven_lite.cc
${protobuf_source_dir}/src/google/protobuf/generated_message_util.cc
${protobuf_source_dir}/src/google/protobuf/implicit_weak_message.cc
@ -9,6 +10,7 @@ set(libprotobuf_lite_files
${protobuf_source_dir}/src/google/protobuf/io/io_win32.cc
${protobuf_source_dir}/src/google/protobuf/io/strtod.cc
${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream.cc
${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl.cc
${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
${protobuf_source_dir}/src/google/protobuf/message_lite.cc
${protobuf_source_dir}/src/google/protobuf/parse_context.cc
@ -36,6 +38,7 @@ set(libprotobuf_lite_includes
${protobuf_source_dir}/src/google/protobuf/io/coded_stream.h
${protobuf_source_dir}/src/google/protobuf/io/strtod.h
${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream.h
${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl.h
${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl_lite.h
${protobuf_source_dir}/src/google/protobuf/message_lite.h
${protobuf_source_dir}/src/google/protobuf/repeated_field.h

View File

@ -17,7 +17,6 @@ set(libprotobuf_files
${protobuf_source_dir}/src/google/protobuf/io/gzip_stream.cc
${protobuf_source_dir}/src/google/protobuf/io/printer.cc
${protobuf_source_dir}/src/google/protobuf/io/tokenizer.cc
${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl.cc
${protobuf_source_dir}/src/google/protobuf/map_field.cc
${protobuf_source_dir}/src/google/protobuf/message.cc
${protobuf_source_dir}/src/google/protobuf/reflection_ops.cc
@ -72,7 +71,6 @@ set(libprotobuf_includes
${protobuf_source_dir}/src/google/protobuf/io/gzip_stream.h
${protobuf_source_dir}/src/google/protobuf/io/printer.h
${protobuf_source_dir}/src/google/protobuf/io/tokenizer.h
${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl.h
${protobuf_source_dir}/src/google/protobuf/map_field.h
${protobuf_source_dir}/src/google/protobuf/message.h
${protobuf_source_dir}/src/google/protobuf/reflection_ops.h

View File

@ -123,8 +123,7 @@ public class ExtensionRegistryFactoryTest extends TestCase {
assertTrue(
"Test is using a non-lite extension",
GeneratedMessage.GeneratedExtension.class.isAssignableFrom(
NonNestedExtension.nonNestedExtension.getClass()));
Extension.class.isAssignableFrom(NonNestedExtension.nonNestedExtension.getClass()));
assertNotNull(
"Extension is registered in masqueraded full registry",
fullRegistry2.findImmutableExtensionByName("protobuf_unittest.nonNestedExtension"));

View File

@ -144,7 +144,7 @@ function getClosureBuilderCommand(exportsFile, outputFile) {
exportsFile + ' > ' + outputFile;
}
gulp.task('dist', gulp.series(['genproto_wellknowntypes'], function (cb) {
gulp.task('dist', gulp.series(['genproto_wellknowntypes'], function(cb) {
// TODO(haberman): minify this more aggressively.
// Will require proper externs/exports.
exec(getClosureBuilderCommand('commonjs/export.js', 'google-protobuf.js'),
@ -179,49 +179,75 @@ gulp.task('commonjs_testdeps', function (cb) {
});
});
gulp.task('make_commonjs_out', gulp.series(['dist', 'genproto_well_known_types_commonjs', 'genproto_group1_commonjs', 'genproto_group2_commonjs', 'genproto_commonjs_wellknowntypes', 'commonjs_asserts', 'commonjs_testdeps', 'genproto_group3_commonjs_strict'], function (cb) {
// TODO(haberman): minify this more aggressively.
// Will require proper externs/exports.
var cmd = "mkdir -p commonjs_out/binary && mkdir -p commonjs_out/test_node_modules && ";
function addTestFile(file) {
cmd += 'node commonjs/rewrite_tests_for_commonjs.js < ' + file +
' > commonjs_out/' + file + '&& ';
}
gulp.task(
'make_commonjs_out',
gulp.series(
[
'dist', 'genproto_well_known_types_commonjs',
'genproto_group1_commonjs', 'genproto_group2_commonjs',
'genproto_commonjs_wellknowntypes', 'commonjs_asserts',
'commonjs_testdeps', 'genproto_group3_commonjs_strict'
],
function(cb) {
// TODO(haberman): minify this more aggressively.
// Will require proper externs/exports.
var cmd =
'mkdir -p commonjs_out/binary && mkdir -p commonjs_out/test_node_modules && ';
function addTestFile(file) {
cmd += 'node commonjs/rewrite_tests_for_commonjs.js < ' + file +
' > commonjs_out/' + file + '&& ';
}
glob.sync('*_test.js').forEach(addTestFile);
glob.sync('binary/*_test.js').forEach(addTestFile);
glob.sync('*_test.js').forEach(addTestFile);
glob.sync('binary/*_test.js').forEach(addTestFile);
exec(cmd +
'cp commonjs/jasmine.json commonjs_out/jasmine.json && ' +
'cp google-protobuf.js commonjs_out/test_node_modules && ' +
'cp commonjs/strict_test.js commonjs_out/strict_test.js &&' +
'cp commonjs/import_test.js commonjs_out/import_test.js',
function (err, stdout, stderr) {
console.log(stdout);
console.log(stderr);
cb(err);
});
}));
exec(
cmd + 'cp commonjs/jasmine.json commonjs_out/jasmine.json && ' +
'cp google-protobuf.js commonjs_out/test_node_modules && ' +
'cp commonjs/strict_test.js commonjs_out/strict_test.js &&' +
'cp commonjs/import_test.js commonjs_out/import_test.js',
function(err, stdout, stderr) {
console.log(stdout);
console.log(stderr);
cb(err);
});
}));
gulp.task('deps', gulp.series(['genproto_well_known_types_closure', 'genproto_group1_closure', 'genproto_group2_closure'], function (cb) {
exec('./node_modules/google-closure-library/closure/bin/build/depswriter.py binary/arith.js binary/constants.js binary/decoder.js binary/encoder.js binary/reader.js binary/utils.js binary/writer.js debug.js map.js message.js node_loader.js test_bootstrap.js > deps.js',
function (err, stdout, stderr) {
console.log(stdout);
console.log(stderr);
cb(err);
});
}));
gulp.task(
'deps',
gulp.series(
[
'genproto_well_known_types_closure', 'genproto_group1_closure',
'genproto_group2_closure'
],
function(cb) {
exec(
'./node_modules/google-closure-library/closure/bin/build/depswriter.py binary/arith.js binary/constants.js binary/decoder.js binary/encoder.js binary/reader.js binary/utils.js binary/writer.js debug.js map.js message.js node_loader.js test_bootstrap.js > deps.js',
function(err, stdout, stderr) {
console.log(stdout);
console.log(stderr);
cb(err);
});
}));
gulp.task('test_closure', gulp.series(['genproto_well_known_types_closure', 'genproto_group1_closure', 'genproto_group2_closure', 'deps'], function (cb) {
exec('JASMINE_CONFIG_PATH=jasmine.json ./node_modules/.bin/jasmine',
function (err, stdout, stderr) {
console.log(stdout);
console.log(stderr);
cb(err);
});
}));
gulp.task(
'test_closure',
gulp.series(
[
'genproto_well_known_types_closure', 'genproto_group1_closure',
'genproto_group2_closure', 'deps'
],
function(cb) {
exec(
'JASMINE_CONFIG_PATH=jasmine.json ./node_modules/.bin/jasmine',
function(err, stdout, stderr) {
console.log(stdout);
console.log(stderr);
cb(err);
});
}));
gulp.task('test_commonjs', gulp.series(['make_commonjs_out'], function (cb) {
gulp.task('test_commonjs', gulp.series(['make_commonjs_out'], function(cb) {
exec('cd commonjs_out && JASMINE_CONFIG_PATH=jasmine.json NODE_PATH=test_node_modules ../node_modules/.bin/jasmine',
function (err, stdout, stderr) {
console.log(stdout);

View File

@ -316,6 +316,18 @@ class TextFormatMessageToStringTests(TextFormatBase):
'payload {{\n {0}\n {1}\n {2}\n {3}\n}}\n'.format(
*formatted_fields))
# Test default float_format has 8 valid digits.
message.payload.optional_float = 1.2345678912
message.payload.optional_double = 1.2345678912
formatted_fields = ['optional_float: 1.2345679',
'optional_double: 1.2345678912',
'repeated_float: -5642', 'repeated_double: 7.89e-5']
text_message = text_format.MessageToString(message)
self.CompareToGoldenText(
self.RemoveRedundantZeros(text_message),
'payload {{\n {0}\n {1}\n {2}\n {3}\n}}\n'.format(
*formatted_fields))
def testMessageToString(self, message_module):
message = message_module.ForeignMessage()
message.c = 123

View File

@ -133,10 +133,10 @@ def MessageToString(message,
# type: (...) -> str
"""Convert protobuf message to text format.
Floating point values can be formatted compactly with 15 digits of
Double values can be formatted compactly with 15 digits of
precision (which is the most that IEEE 754 "double" can guarantee)
using float_format='.15g'. To ensure that converting to text and back to a
proto will result in an identical value, float_format='.17g' should be used.
using double_format='.15g'. To ensure that converting to text and back to a
proto will result in an identical value, double_format='.17g' should be used.
Args:
message: The protocol buffers message.
@ -153,11 +153,12 @@ def MessageToString(message,
determined by the extension number. By default, use the field number
order.
float_format: If set, use this to specify float field formatting
(per the "Format Specification Mini-Language"); otherwise, str() is used.
Also affect double field if double_format is not set.
(per the "Format Specification Mini-Language"); otherwise, 8 valid digits
is used (default '.8g'). Also affect double field if double_format is
not set but float_format is set.
double_format: If set, use this to specify double field formatting
(per the "Format Specification Mini-Language"); otherwise, float_format
is used.
(per the "Format Specification Mini-Language"); if it is not set but
float_format is set, use float_format. Otherwise, use str()
use_field_number: If True, print field numbers instead of names.
descriptor_pool: A DescriptorPool used to resolve Any types.
indent: The initial indent level, in terms of spaces, for pretty print.
@ -322,10 +323,10 @@ class _Printer(object):
print_unknown_fields=False):
"""Initialize the Printer.
Floating point values can be formatted compactly with 15 digits of
precision (which is the most that IEEE 754 "double" can guarantee)
using float_format='.15g'. To ensure that converting to text and back to a
proto will result in an identical value, float_format='.17g' should be used.
Double values can be formatted compactly with 15 digits of precision
(which is the most that IEEE 754 "double" can guarantee) using
double_format='.15g'. To ensure that converting to text and back to a proto
will result in an identical value, double_format='.17g' should be used.
Args:
out: To record the text format result.
@ -340,11 +341,13 @@ class _Printer(object):
use_index_order: If True, print fields of a proto message using the order
defined in source code instead of the field number. By default, use the
field number order.
float_format: If set, use this to specify floating point number formatting
(per the "Format Specification Mini-Language"); otherwise, str() is
used. Also affect double field if double_format is not set.
double_format: If set, use this to specify double field formatting;
otherwise, float_format is used.
float_format: If set, use this to specify float field formatting
(per the "Format Specification Mini-Language"); otherwise, 8 valid
digits is used (default '.8g'). Also affect double field if
double_format is not set but float_format is set.
double_format: If set, use this to specify double field formatting
(per the "Format Specification Mini-Language"); if it is not set but
float_format is set, use float_format. Otherwise, str() is used.
use_field_number: If True, print field numbers instead of names.
descriptor_pool: A DescriptorPool used to resolve Any types.
message_formatter: A function(message, indent, as_one_line): unicode|None
@ -589,9 +592,11 @@ class _Printer(object):
out.write('true')
else:
out.write('false')
elif (field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_FLOAT and
self.float_format is not None):
out.write('{1:{0}}'.format(self.float_format, value))
elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_FLOAT:
if self.float_format is not None:
out.write('{1:{0}}'.format(self.float_format, value))
else:
out.write(str(float(format(value, '.8g'))))
elif (field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_DOUBLE and
self.double_format is not None):
out.write('{1:{0}}'.format(self.double_format, value))

View File

@ -202,6 +202,7 @@ libprotobuf_lite_la_SOURCES = \
google/protobuf/any_lite.cc \
google/protobuf/arena.cc \
google/protobuf/extension_set.cc \
google/protobuf/generated_enum_util.cc \
google/protobuf/generated_message_util.cc \
google/protobuf/generated_message_table_driven_lite.h \
google/protobuf/generated_message_table_driven_lite.cc \
@ -214,6 +215,7 @@ libprotobuf_lite_la_SOURCES = \
google/protobuf/io/coded_stream_inl.h \
google/protobuf/io/strtod.cc \
google/protobuf/io/zero_copy_stream.cc \
google/protobuf/io/zero_copy_stream_impl.cc \
google/protobuf/io/zero_copy_stream_impl_lite.cc
libprotobuf_la_LIBADD = $(PTHREAD_LIBS) $(LIBATOMIC_LIBS)
@ -258,7 +260,6 @@ libprotobuf_la_SOURCES = \
google/protobuf/io/gzip_stream.cc \
google/protobuf/io/printer.cc \
google/protobuf/io/tokenizer.cc \
google/protobuf/io/zero_copy_stream_impl.cc \
google/protobuf/compiler/importer.cc \
google/protobuf/compiler/parser.cc \
google/protobuf/util/delimited_message_util.cc \

View File

@ -57,6 +57,17 @@ bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
}
return max_value != kint32max;
}
// Returns the number of unique numeric enum values. This is less than
// descriptor->value_count() when there are aliased values.
int CountUniqueValues(const EnumDescriptor* descriptor) {
std::set<int> values;
for (int i = 0; i < descriptor->value_count(); ++i) {
values.insert(descriptor->value(i)->number());
}
return values.size();
}
} // namespace
EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
@ -143,25 +154,42 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
format(
"$dllexport_decl $const ::$proto_ns$::EnumDescriptor* "
"$classname$_descriptor();\n");
// The _Name and _Parse methods
// Support a stricter, type-checked enum-to-string method that
// statically checks whether the parameter is the exact enum type or is
// an integral type.
}
// The _Name and _Parse functions. The lite implementation is table-based, so
// we make sure to keep the tables hidden in the .cc file.
if (!HasDescriptorMethods(descriptor_->file(), options_)) {
format("const std::string& $classname$_Name($classname$ value);\n");
}
// The _Name() function accepts the enum type itself but also any integral
// type.
format(
"template<typename T>\n"
"inline const std::string& $classname$_Name(T enum_t_value) {\n"
" static_assert(::std::is_same<T, $classname$>::value ||\n"
" ::std::is_integral<T>::value,\n"
" \"Incorrect type passed to function $classname$_Name.\");\n");
if (HasDescriptorMethods(descriptor_->file(), options_)) {
format(
"template<typename T>\n"
"inline const std::string& $classname$_Name(T enum_t_value) {\n"
" static_assert(::std::is_same<T, $classname$>::value ||\n"
" ::std::is_integral<T>::value,\n"
" \"Incorrect type passed to function $classname$_Name.\");\n"
" return ::$proto_ns$::internal::NameOfEnum(\n"
" $classname$_descriptor(), enum_t_value);\n"
"}\n");
" $classname$_descriptor(), enum_t_value);\n");
} else {
format(
" return $classname$_Name(static_cast<$classname$>(enum_t_value));\n");
}
format("}\n");
if (HasDescriptorMethods(descriptor_->file(), options_)) {
format(
"inline bool $classname$_Parse(\n"
" const std::string& name, $classname$* value) {\n"
" return ::$proto_ns$::internal::ParseNamedEnum<$classname$>(\n"
" $classname$_descriptor(), name, value);\n"
"}\n");
} else {
format(
"bool $classname$_Parse(\n"
" const std::string& name, $classname$* value);\n");
}
}
@ -216,24 +244,21 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) const {
"$nested_name$_descriptor() {\n"
" return $classname$_descriptor();\n"
"}\n");
// Support a stricter, type-checked enum-to-string method that
// statically checks whether the parameter is the exact enum type or is
// an integral type.
format(
"template<typename T>\n"
"static inline const std::string& $nested_name$_Name(T enum_t_value) "
"{\n"
" static_assert(::std::is_same<T, $resolved_name$>::value ||\n"
" ::std::is_integral<T>::value,\n"
" \"Incorrect type passed to function $nested_name$_Name.\");\n"
" return $classname$_Name(enum_t_value);\n"
"}\n");
format(
"static inline bool $nested_name$_Parse(const std::string& name,\n"
" $resolved_name$* value) {\n"
" return $classname$_Parse(name, value);\n"
"}\n");
}
format(
"template<typename T>\n"
"static inline const std::string& $nested_name$_Name(T enum_t_value) {\n"
" static_assert(::std::is_same<T, $resolved_name$>::value ||\n"
" ::std::is_integral<T>::value,\n"
" \"Incorrect type passed to function $nested_name$_Name.\");\n"
" return $classname$_Name(enum_t_value);\n"
"}\n");
format(
"static inline bool $nested_name$_Parse(const std::string& name,\n"
" $resolved_name$* value) {\n"
" return $classname$_Parse(name, value);\n"
"}\n");
}
void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) {
@ -274,6 +299,104 @@ void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) {
"}\n"
"\n");
if (!HasDescriptorMethods(descriptor_->file(), options_)) {
// In lite mode (where descriptors are unavailable), we generate separate
// tables for mapping between enum names and numbers. The _entries table
// contains the bulk of the data and is sorted by name, while
// _entries_by_number is sorted by number and just contains pointers into
// _entries. The two tables allow mapping from name to number and number to
// name, both in time logarithmic in the number of enum entries. This could
// probably be made faster, but for now the tables are intended to be simple
// and compact.
//
// Enums with allow_alias = true support multiple entries with the same
// numerical value. In cases where there are multiple names for the same
// number, we treat the first name appearing in the .proto file as the
// canonical one.
std::map<std::string, int> name_to_number;
std::map<int, std::string> number_to_canonical_name;
for (int i = 0; i < descriptor_->value_count(); i++) {
const EnumValueDescriptor* value = descriptor_->value(i);
name_to_number.emplace(value->name(), value->number());
// The same number may appear with multiple names, so we use emplace() to
// let the first name win.
number_to_canonical_name.emplace(value->number(), value->name());
}
format(
"static ::$proto_ns$::internal::ExplicitlyConstructed<std::string> "
"$classname$_strings[$1$] = {};\n\n",
CountUniqueValues(descriptor_));
// We concatenate all the names for a given enum into one big string
// literal. If instead we store an array of string literals, the linker
// seems to put all enum strings for a given .proto file in the same
// section, which hinders its ability to strip out unused strings.
format("static const char $classname$_names[] =");
for (const auto& p : name_to_number) {
format("\n \"$1$\"", p.first);
}
format(";\n\n");
format(
"static const ::$proto_ns$::internal::EnumEntry $classname$_entries[] "
"= {\n");
int i = 0;
std::map<int, int> number_to_index;
int data_index = 0;
for (const auto& p : name_to_number) {
format(" { {$classname$_names + $1$, $2$}, $3$ },\n", data_index,
p.first.size(), p.second);
if (number_to_canonical_name[p.second] == p.first) {
number_to_index.emplace(p.second, i);
}
++i;
data_index += p.first.size();
}
format(
"};\n"
"\n"
"static const int $classname$_entries_by_number[] = {\n");
for (const auto& p : number_to_index) {
format(" $1$, // $2$ -> $3$\n", p.second, p.first,
number_to_canonical_name[p.first]);
}
format(
"};\n"
"\n");
format(
"const std::string& $classname$_Name(\n"
" $classname$ value) {\n"
" static const bool dummy =\n"
" ::$proto_ns$::internal::InitializeEnumStrings(\n"
" $classname$_entries,\n"
" $classname$_entries_by_number,\n"
" $1$, $classname$_strings);\n"
" (void) dummy;\n"
" int idx = ::$proto_ns$::internal::LookUpEnumName(\n"
" $classname$_entries,\n"
" $classname$_entries_by_number,\n"
" $1$, value);\n"
" return idx == -1 ? ::$proto_ns$::internal::GetEmptyString() :\n"
" $classname$_strings[idx].get();\n"
"}\n",
CountUniqueValues(descriptor_));
format(
"bool $classname$_Parse(\n"
" const std::string& name, $classname$* value) {\n"
" int int_value;\n"
" bool success = ::$proto_ns$::internal::LookUpEnumValue(\n"
" $classname$_entries, $1$, name, &int_value);\n"
" if (success) {\n"
" *value = static_cast<$classname$>(int_value);\n"
" }\n"
" return success;\n"
"}\n",
descriptor_->value_count());
}
if (descriptor_->containing_type() != NULL) {
std::string parent = ClassName(descriptor_->containing_type(), false);
// Before C++17, we must define the static constants which were

View File

@ -892,11 +892,17 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) {
protodef_name, file_data.size(), sccs_.size(), num_deps,
message_generators_.size());
format(
"// Force running AddDescriptors() at dynamic initialization time.\n"
"static bool $1$ = ("
" ::$proto_ns$::internal::AddDescriptors(&$desc_table$), true);\n",
UniqueName("dynamic_init_dummy", file_, options_));
// For descriptor.proto we want to avoid doing any dynamic initialization,
// because in some situations that would otherwise pull in a lot of
// unnecessary code that can't be stripped by --gc-sections. Descriptor
// initialization will still be performed lazily when it's needed.
if (file_->name() != "net/proto2/proto/descriptor.proto") {
format(
"// Force running AddDescriptors() at dynamic initialization time.\n"
"static bool $1$ = ("
" ::$proto_ns$::internal::AddDescriptors(&$desc_table$), true);\n",
UniqueName("dynamic_init_dummy", file_, options_));
}
}
void FileGenerator::GenerateInitForSCC(const SCC* scc, io::Printer* printer) {

View File

@ -65,15 +65,12 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
switch (val->cpp_type()) {
case FieldDescriptor::CPPTYPE_MESSAGE:
(*variables)["val_cpp"] = FieldMessageTypeName(val, options);
(*variables)["wrapper"] = "MapEntryWrapper";
break;
case FieldDescriptor::CPPTYPE_ENUM:
(*variables)["val_cpp"] = ClassName(val->enum_type(), true);
(*variables)["wrapper"] = "MapEnumEntryWrapper";
break;
default:
(*variables)["val_cpp"] = PrimitiveTypeName(options, val->cpp_type());
(*variables)["wrapper"] = "MapEntryWrapper";
}
(*variables)["key_wire_type"] =
"TYPE_" + ToUpper(DeclaredTypeMethodName(key->type()));
@ -250,17 +247,16 @@ static void GenerateSerializationLoop(const Formatter& format, bool string_key,
}
format.Indent();
format(
"$map_classname$::$wrapper$ entry(nullptr, $1$->first, $1$->second);\n",
ptr);
if (to_array) {
format(
"target = ::$proto_ns$::internal::WireFormatLite::InternalWrite"
"$declared_type$NoVirtualToArray($number$, entry, target);\n");
"target = $map_classname$::Funcs::SerializeToArray($number$, "
"$1$->first, $1$->second, target);\n",
ptr);
} else {
format(
"::$proto_ns$::internal::WireFormatLite::Write$stream_writer$($number$,"
" entry, output);\n");
"$map_classname$::Funcs::SerializeToCodedStream($number$, "
"$1$->first, $1$->second, output);\n",
ptr);
}
if (string_key || string_value) {
@ -370,9 +366,8 @@ void MapFieldGenerator::GenerateByteSize(io::Printer* printer) const {
"for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
" it = this->$name$().begin();\n"
" it != this->$name$().end(); ++it) {\n"
" $map_classname$::$wrapper$ entry(nullptr, it->first, it->second);\n"
" total_size += ::$proto_ns$::internal::WireFormatLite::\n"
" $declared_type$SizeNoVirtual(entry);\n"
" total_size += $map_classname$::Funcs::ByteSizeLong(it->first, "
"it->second);\n"
"}\n");
}

View File

@ -1335,7 +1335,10 @@ DescriptorPool* DescriptorPool::internal_generated_pool() {
}
const DescriptorPool* DescriptorPool::generated_pool() {
return internal_generated_pool();
const DescriptorPool* pool = internal_generated_pool();
// Ensure that descriptor.proto has been registered in the generated pool.
DescriptorProto::descriptor();
return pool;
}

View File

@ -0,0 +1,95 @@
// 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.
#include <google/protobuf/generated_enum_util.h>
#include <algorithm>
#include <google/protobuf/generated_message_util.h>
namespace google {
namespace protobuf {
namespace internal {
namespace {
bool EnumCompareByName(const EnumEntry& a, const EnumEntry& b) {
return StringPiece(a.name) < StringPiece(b.name);
}
// Gets the numeric value of the EnumEntry at the given index, but returns a
// special value for the index -1. This gives a way to use std::lower_bound on a
// sorted array of indices while searching for value that we associate with -1.
int GetValue(const EnumEntry* enums, int i, int target) {
if (i == -1) {
return target;
} else {
return enums[i].value;
}
}
} // namespace
bool LookUpEnumValue(const EnumEntry* enums, size_t size,
StringPiece name, int* value) {
EnumEntry target{name, 0};
auto it = std::lower_bound(enums, enums + size, target, EnumCompareByName);
if (it != enums + size && it->name == name) {
*value = it->value;
return true;
}
return false;
}
int LookUpEnumName(const EnumEntry* enums, const int* sorted_indices,
size_t size, int value) {
auto comparator = [enums, value](int a, int b) {
return GetValue(enums, a, value) < GetValue(enums, b, value);
};
auto it =
std::lower_bound(sorted_indices, sorted_indices + size, -1, comparator);
if (it != sorted_indices + size && enums[*it].value == value) {
return it - sorted_indices;
}
return -1;
}
bool InitializeEnumStrings(
const EnumEntry* enums, const int* sorted_indices, size_t size,
internal::ExplicitlyConstructed<std::string>* enum_strings) {
for (int i = 0; i < size; ++i) {
enum_strings[i].Construct(enums[sorted_indices[i]].name);
internal::OnShutdownDestroyString(enum_strings[i].get_mutable());
}
return true;
}
} // namespace internal
} // namespace protobuf
} // namespace google

View File

@ -33,6 +33,11 @@
#include <type_traits>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/port_def.inc>
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
@ -45,7 +50,34 @@ namespace protobuf {
template <typename T>
struct is_proto_enum : ::std::false_type {};
namespace internal {
// The table entry format for storing enum name-to-value mapping used with lite
// protos. This struct and the following related functions should only be used
// by protobuf generated code.
struct EnumEntry {
StringPiece name;
int value;
};
// Looks up a numeric enum value given the string name.
PROTOBUF_EXPORT bool LookUpEnumValue(const EnumEntry* enums, size_t size,
StringPiece name, int* value);
// Looks up an enum name given the numeric value.
PROTOBUF_EXPORT int LookUpEnumName(const EnumEntry* enums,
const int* sorted_indices, size_t size,
int value);
// Initializes the list of enum names in std::string form.
PROTOBUF_EXPORT bool InitializeEnumStrings(
const EnumEntry* enums, const int* sorted_indices, size_t size,
internal::ExplicitlyConstructed<std::string>* enum_strings);
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__

View File

@ -203,8 +203,8 @@ GeneratedMessageReflection::GeneratedMessageReflection(
const DescriptorPool* pool, MessageFactory* factory)
: descriptor_(descriptor),
schema_(schema),
descriptor_pool_((pool == NULL) ? DescriptorPool::generated_pool()
: pool),
descriptor_pool_(
(pool == nullptr) ? DescriptorPool::internal_generated_pool() : pool),
message_factory_(factory),
last_non_weak_field_index_(-1) {
last_non_weak_field_index_ = descriptor_->field_count() - 1;
@ -2250,7 +2250,7 @@ class AssignDescriptorsHelper {
descriptor,
MigrationToReflectionSchema(default_instance_data_, offsets_,
*schemas_),
DescriptorPool::generated_pool(), factory_);
DescriptorPool::internal_generated_pool(), factory_);
for (int i = 0; i < descriptor->enum_type_count(); i++) {
AssignEnumDescriptor(descriptor->enum_type(i));
}
@ -2317,7 +2317,8 @@ void AssignDescriptorsImpl(const DescriptorTable* table) {
}
// Fill the arrays with pointers to descriptors and reflection classes.
const FileDescriptor* file =
DescriptorPool::generated_pool()->FindFileByName(table->filename);
DescriptorPool::internal_generated_pool()->FindFileByName(
table->filename);
GOOGLE_CHECK(file != NULL);
MessageFactory* factory = MessageFactory::generated_factory();

View File

@ -1097,5 +1097,99 @@ TEST(Lite, DebugString) {
EXPECT_NE(message1.DebugString(), message2.DebugString());
}
TEST(Lite, EnumValueToName) {
EXPECT_EQ("FOREIGN_LITE_FOO", protobuf_unittest::ForeignEnumLite_Name(
protobuf_unittest::FOREIGN_LITE_FOO));
EXPECT_EQ("FOREIGN_LITE_BAR", protobuf_unittest::ForeignEnumLite_Name(
protobuf_unittest::FOREIGN_LITE_BAR));
EXPECT_EQ("FOREIGN_LITE_BAZ", protobuf_unittest::ForeignEnumLite_Name(
protobuf_unittest::FOREIGN_LITE_BAZ));
EXPECT_EQ("", protobuf_unittest::ForeignEnumLite_Name(0));
EXPECT_EQ("", protobuf_unittest::ForeignEnumLite_Name(999));
}
TEST(Lite, NestedEnumValueToName) {
EXPECT_EQ("FOO", protobuf_unittest::TestAllTypesLite::NestedEnum_Name(
protobuf_unittest::TestAllTypesLite::FOO));
EXPECT_EQ("BAR", protobuf_unittest::TestAllTypesLite::NestedEnum_Name(
protobuf_unittest::TestAllTypesLite::BAR));
EXPECT_EQ("BAZ", protobuf_unittest::TestAllTypesLite::NestedEnum_Name(
protobuf_unittest::TestAllTypesLite::BAZ));
EXPECT_EQ("", protobuf_unittest::TestAllTypesLite::NestedEnum_Name(0));
EXPECT_EQ("", protobuf_unittest::TestAllTypesLite::NestedEnum_Name(999));
}
TEST(Lite, EnumNameToValue) {
protobuf_unittest::ForeignEnumLite value;
ASSERT_TRUE(
protobuf_unittest::ForeignEnumLite_Parse("FOREIGN_LITE_FOO", &value));
EXPECT_EQ(protobuf_unittest::FOREIGN_LITE_FOO, value);
ASSERT_TRUE(
protobuf_unittest::ForeignEnumLite_Parse("FOREIGN_LITE_BAR", &value));
EXPECT_EQ(protobuf_unittest::FOREIGN_LITE_BAR, value);
ASSERT_TRUE(
protobuf_unittest::ForeignEnumLite_Parse("FOREIGN_LITE_BAZ", &value));
EXPECT_EQ(protobuf_unittest::FOREIGN_LITE_BAZ, value);
// Non-existent values
EXPECT_FALSE(protobuf_unittest::ForeignEnumLite_Parse("E", &value));
EXPECT_FALSE(
protobuf_unittest::ForeignEnumLite_Parse("FOREIGN_LITE_C", &value));
EXPECT_FALSE(protobuf_unittest::ForeignEnumLite_Parse("G", &value));
}
TEST(Lite, NestedEnumNameToValue) {
protobuf_unittest::TestAllTypesLite::NestedEnum value;
ASSERT_TRUE(
protobuf_unittest::TestAllTypesLite::NestedEnum_Parse("FOO", &value));
EXPECT_EQ(protobuf_unittest::TestAllTypesLite::FOO, value);
ASSERT_TRUE(
protobuf_unittest::TestAllTypesLite::NestedEnum_Parse("BAR", &value));
EXPECT_EQ(protobuf_unittest::TestAllTypesLite::BAR, value);
ASSERT_TRUE(
protobuf_unittest::TestAllTypesLite::NestedEnum_Parse("BAZ", &value));
EXPECT_EQ(protobuf_unittest::TestAllTypesLite::BAZ, value);
// Non-existent values
EXPECT_FALSE(
protobuf_unittest::TestAllTypesLite::NestedEnum_Parse("A", &value));
EXPECT_FALSE(
protobuf_unittest::TestAllTypesLite::NestedEnum_Parse("C", &value));
EXPECT_FALSE(
protobuf_unittest::TestAllTypesLite::NestedEnum_Parse("G", &value));
}
TEST(Lite, AliasedEnum) {
// Enums with allow_alias = true can have multiple entries with the same
// value.
EXPECT_EQ("FOO1", protobuf_unittest::DupEnum::TestEnumWithDupValueLite_Name(
protobuf_unittest::DupEnum::FOO1));
EXPECT_EQ("FOO1", protobuf_unittest::DupEnum::TestEnumWithDupValueLite_Name(
protobuf_unittest::DupEnum::FOO2));
EXPECT_EQ("BAR1", protobuf_unittest::DupEnum::TestEnumWithDupValueLite_Name(
protobuf_unittest::DupEnum::BAR1));
EXPECT_EQ("BAR1", protobuf_unittest::DupEnum::TestEnumWithDupValueLite_Name(
protobuf_unittest::DupEnum::BAR2));
EXPECT_EQ("BAZ", protobuf_unittest::DupEnum::TestEnumWithDupValueLite_Name(
protobuf_unittest::DupEnum::BAZ));
EXPECT_EQ("", protobuf_unittest::DupEnum::TestEnumWithDupValueLite_Name(999));
protobuf_unittest::DupEnum::TestEnumWithDupValueLite value;
ASSERT_TRUE(
protobuf_unittest::DupEnum::TestEnumWithDupValueLite_Parse("FOO1", &value));
EXPECT_EQ(protobuf_unittest::DupEnum::FOO1, value);
value = static_cast<protobuf_unittest::DupEnum::TestEnumWithDupValueLite>(0);
ASSERT_TRUE(
protobuf_unittest::DupEnum::TestEnumWithDupValueLite_Parse("FOO2", &value));
EXPECT_EQ(protobuf_unittest::DupEnum::FOO2, value);
}
} // namespace protobuf
} // namespace google

View File

@ -937,7 +937,8 @@ class Map {
// Return a randomish value.
size_type Seed() const {
size_type s = static_cast<size_type>(reinterpret_cast<uintptr_t>(this));
#if defined(__x86_64__) && defined(__GNUC__) && !defined(GOOGLE_PROTOBUF_NO_RDTSC)
#if defined(__x86_64__) && defined(__GNUC__) && \
!defined(GOOGLE_PROTOBUF_NO_RDTSC)
uint32 hi, lo;
asm("rdtsc" : "=a"(lo), "=d"(hi));
s += ((static_cast<uint64>(hi) << 32) | lo);

View File

@ -101,6 +101,51 @@ struct MoveHelper<false, false, true, T> { // strings and similar
}
};
// Functions for operating on a map entry. Does not contain any representation
// (this class is not intended to be instantiated).
template <typename Key, typename Value, WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
struct MapEntryFuncs {
typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler;
static const int kKeyFieldNumber = 1;
static const int kValueFieldNumber = 2;
static void SerializeToCodedStream(int field_number, const Key& key,
const Value& value,
io::CodedOutputStream* output) {
WireFormatLite::WriteTag(field_number,
WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
output->WriteVarint32(GetCachedSize(key, value));
KeyTypeHandler::Write(kKeyFieldNumber, key, output);
ValueTypeHandler::Write(kValueFieldNumber, value, output);
}
static ::google::protobuf::uint8* SerializeToArray(int field_number, const Key& key,
const Value& value, ::google::protobuf::uint8* output) {
output = WireFormatLite::WriteTagToArray(
field_number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
output = io::CodedOutputStream::WriteVarint32ToArray(
static_cast<uint32>(GetCachedSize(key, value)), output);
output = KeyTypeHandler::WriteToArray(kKeyFieldNumber, key, output);
output = ValueTypeHandler::WriteToArray(kValueFieldNumber, value, output);
return output;
}
static size_t ByteSizeLong(const Key& key, const Value& value) {
// Tags for key and value will both be one byte (field numbers 1 and 2).
size_t inner_length =
2 + KeyTypeHandler::ByteSize(key) + ValueTypeHandler::ByteSize(value);
return inner_length + io::CodedOutputStream::VarintSize32(inner_length);
}
static int GetCachedSize(const Key& key, const Value& value) {
// Tags for key and value will both be one byte (field numbers 1 and 2).
return 2 + KeyTypeHandler::GetCachedSize(key) +
ValueTypeHandler::GetCachedSize(value);
}
};
// MapEntryImpl is used to implement parsing and serialization of map entries.
// It uses Curious Recursive Template Pattern (CRTP) to provide the type of
// the eventual code to the template code.
@ -108,6 +153,9 @@ template <typename Derived, typename Base, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
class MapEntryImpl : public Base {
public:
typedef MapEntryFuncs<Key, Value, kKeyFieldType, kValueFieldType> Funcs;
protected:
// Provide utilities to parse/serialize key/value. Provide utilities to
// manipulate internal stored type.
@ -350,20 +398,6 @@ class MapEntryImpl : public Base {
Arena* GetArena() const override { return GetArenaNoVirtual(); }
// Create a MapEntryImpl for given key and value from Map in
// serialization. This function is only called when value is enum. Enum is
// treated differently because its type in MapEntry is int and its type in
// Map is enum. We cannot create a reference to int from an enum.
static Derived* EnumWrap(const Key& key, const Value value, Arena* arena) {
return Arena::CreateMessage<MapEnumEntryWrapper>(arena, key, value);
}
// Like above, but for all the other types. This avoids value copy to create
// MapEntryImpl from Map in serialization.
static Derived* Wrap(const Key& key, const Value& value, Arena* arena) {
return Arena::CreateMessage<MapEntryWrapper>(arena, key, value);
}
// Parsing using MergePartialFromCodedStream, above, is not as
// efficient as it could be. This helper class provides a speedier way.
template <typename MapField, typename Map>
@ -535,71 +569,6 @@ class MapEntryImpl : public Base {
void clear_has_value() { _has_bits_[0] &= ~0x00000002u; }
public:
// Serializing a generated message containing map field involves serializing
// key-value pairs from Map. The wire format of each key-value pair
// after serialization should be the same as that of a MapEntry message
// containing the same key and value inside it. However, Map doesn't
// store key and value as MapEntry message, which disables us to use existing
// code to serialize message. In order to use existing code to serialize
// message, we need to construct a MapEntry from key-value pair. But it
// involves copy of key and value to construct a MapEntry. In order to avoid
// this copy in constructing a MapEntry, we need the following class which
// only takes references of given key and value.
class MapEntryWrapper : public Derived {
typedef Derived BaseClass;
typedef typename BaseClass::KeyMapEntryAccessorType KeyMapEntryAccessorType;
typedef
typename BaseClass::ValueMapEntryAccessorType ValueMapEntryAccessorType;
public:
MapEntryWrapper(Arena* arena, const Key& key, const Value& value)
: Derived(arena), key_(key), value_(value) {
BaseClass::set_has_key();
BaseClass::set_has_value();
}
inline const KeyMapEntryAccessorType& key() const override { return key_; }
inline const ValueMapEntryAccessorType& value() const override {
return value_;
}
private:
const Key& key_;
const Value& value_;
friend class ::PROTOBUF_NAMESPACE_ID::Arena;
typedef void InternalArenaConstructable_;
typedef void DestructorSkippable_;
};
// Like above, but for enum value only, which stores value instead of
// reference of value field inside. This is needed because the type of value
// field in constructor is an enum, while we need to store it as an int. If we
// initialize a reference to int with a reference to enum, compiler will
// generate a temporary int from enum and initialize the reference to int with
// the temporary.
class MapEnumEntryWrapper : public Derived {
typedef Derived BaseClass;
typedef typename BaseClass::KeyMapEntryAccessorType KeyMapEntryAccessorType;
typedef
typename BaseClass::ValueMapEntryAccessorType ValueMapEntryAccessorType;
public:
MapEnumEntryWrapper(Arena* arena, const Key& key, const Value& value)
: Derived(arena), key_(key), value_(value) {
BaseClass::set_has_key();
BaseClass::set_has_value();
}
inline const KeyMapEntryAccessorType& key() const { return key_; }
inline const ValueMapEntryAccessorType& value() const { return value_; }
private:
const KeyMapEntryAccessorType& key_;
const ValueMapEntryAccessorType value_;
friend class ::PROTOBUF_NAMESPACE_ID::Arena;
typedef void DestructorSkippable_;
};
inline Arena* GetArenaNoVirtual() const { return arena_; }
public: // Needed for constructing tables

View File

@ -225,9 +225,6 @@ class MapField : public TypeDefinedMapFieldBase<Key, T> {
// Define message type for internal repeated field.
typedef Derived EntryType;
typedef MapEntryLite<Derived, Key, T, kKeyFieldType, kValueFieldType,
default_enum_value>
EntryLiteType;
// Define abbreviation for parent MapFieldLite
typedef MapFieldLite<Derived, Key, T, kKeyFieldType, kValueFieldType,

View File

@ -143,26 +143,6 @@ bool Message::MergePartialFromCodedStream(io::CodedInputStream* input) {
}
#endif
bool Message::ParseFromFileDescriptor(int file_descriptor) {
io::FileInputStream input(file_descriptor);
return ParseFromZeroCopyStream(&input) && input.GetErrno() == 0;
}
bool Message::ParsePartialFromFileDescriptor(int file_descriptor) {
io::FileInputStream input(file_descriptor);
return ParsePartialFromZeroCopyStream(&input) && input.GetErrno() == 0;
}
bool Message::ParseFromIstream(std::istream* input) {
io::IstreamInputStream zero_copy_input(input);
return ParseFromZeroCopyStream(&zero_copy_input) && input->eof();
}
bool Message::ParsePartialFromIstream(std::istream* input) {
io::IstreamInputStream zero_copy_input(input);
return ParsePartialFromZeroCopyStream(&zero_copy_input) && input->eof();
}
#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
namespace internal {
@ -547,7 +527,6 @@ const char* Message::_InternalParse(const char* ptr,
}
#endif // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
void Message::SerializeWithCachedSizes(io::CodedOutputStream* output) const {
const internal::SerializationTable* table =
static_cast<const internal::SerializationTable*>(InternalGetTable());
@ -574,30 +553,6 @@ size_t Message::SpaceUsedLong() const {
return GetReflection()->SpaceUsedLong(*this);
}
bool Message::SerializeToFileDescriptor(int file_descriptor) const {
io::FileOutputStream output(file_descriptor);
return SerializeToZeroCopyStream(&output) && output.Flush();
}
bool Message::SerializePartialToFileDescriptor(int file_descriptor) const {
io::FileOutputStream output(file_descriptor);
return SerializePartialToZeroCopyStream(&output) && output.Flush();
}
bool Message::SerializeToOstream(std::ostream* output) const {
{
io::OstreamOutputStream zero_copy_output(output);
if (!SerializeToZeroCopyStream(&zero_copy_output)) return false;
}
return output->good();
}
bool Message::SerializePartialToOstream(std::ostream* output) const {
io::OstreamOutputStream zero_copy_output(output);
return SerializePartialToZeroCopyStream(&zero_copy_output);
}
// =============================================================================
// Reflection and associated Template Specializations

View File

@ -285,35 +285,6 @@ class PROTOBUF_EXPORT Message : public MessageLite {
// Convenience function useful in GDB. Prints DebugString() to stdout.
void PrintDebugString() const;
// Heavy I/O -------------------------------------------------------
// Additional parsing and serialization methods not implemented by
// MessageLite because they are not supported by the lite library.
// Parse a protocol buffer from a file descriptor. If successful, the entire
// input will be consumed.
bool ParseFromFileDescriptor(int file_descriptor);
// Like ParseFromFileDescriptor(), but accepts messages that are missing
// required fields.
bool ParsePartialFromFileDescriptor(int file_descriptor);
// Parse a protocol buffer from a C++ istream. If successful, the entire
// input will be consumed.
bool ParseFromIstream(std::istream* input);
// Like ParseFromIstream(), but accepts messages that are missing
// required fields.
bool ParsePartialFromIstream(std::istream* input);
// Serialize the message and write it to the given file descriptor. All
// required fields must be set.
bool SerializeToFileDescriptor(int file_descriptor) const;
// Like SerializeToFileDescriptor(), but allows missing required fields.
bool SerializePartialToFileDescriptor(int file_descriptor) const;
// Serialize the message and write it to the given C++ ostream. All
// required fields must be set.
bool SerializeToOstream(std::ostream* output) const;
// Like SerializeToOstream(), but allows missing required fields.
bool SerializePartialToOstream(std::ostream* output) const;
// Reflection-based methods ----------------------------------------
// These methods are pure-virtual in MessageLite, but Message provides
// reflection-based default implementations.

View File

@ -33,6 +33,8 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/message_lite.h>
#include <climits>
#include <cstdint>
#include <string>
@ -43,11 +45,11 @@
#include <google/protobuf/parse_context.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/stubs/strutil.h>
@ -276,6 +278,26 @@ bool MessageLite::ParsePartialFromZeroCopyStream(
return ParseFrom<kParsePartial>(input);
}
bool MessageLite::ParseFromFileDescriptor(int file_descriptor) {
io::FileInputStream input(file_descriptor);
return ParseFromZeroCopyStream(&input) && input.GetErrno() == 0;
}
bool MessageLite::ParsePartialFromFileDescriptor(int file_descriptor) {
io::FileInputStream input(file_descriptor);
return ParsePartialFromZeroCopyStream(&input) && input.GetErrno() == 0;
}
bool MessageLite::ParseFromIstream(std::istream* input) {
io::IstreamInputStream zero_copy_input(input);
return ParseFromZeroCopyStream(&zero_copy_input) && input->eof();
}
bool MessageLite::ParsePartialFromIstream(std::istream* input) {
io::IstreamInputStream zero_copy_input(input);
return ParsePartialFromZeroCopyStream(&zero_copy_input) && input->eof();
}
bool MessageLite::MergePartialFromBoundedZeroCopyStream(
io::ZeroCopyInputStream* input, int size) {
return ParseFrom<kMergePartial>(internal::BoundedZCIS{input, size});
@ -394,6 +416,29 @@ bool MessageLite::SerializePartialToZeroCopyStream(
return SerializePartialToCodedStream(&encoder);
}
bool MessageLite::SerializeToFileDescriptor(int file_descriptor) const {
io::FileOutputStream output(file_descriptor);
return SerializeToZeroCopyStream(&output) && output.Flush();
}
bool MessageLite::SerializePartialToFileDescriptor(int file_descriptor) const {
io::FileOutputStream output(file_descriptor);
return SerializePartialToZeroCopyStream(&output) && output.Flush();
}
bool MessageLite::SerializeToOstream(std::ostream* output) const {
{
io::OstreamOutputStream zero_copy_output(output);
if (!SerializeToZeroCopyStream(&zero_copy_output)) return false;
}
return output->good();
}
bool MessageLite::SerializePartialToOstream(std::ostream* output) const {
io::OstreamOutputStream zero_copy_output(output);
return SerializePartialToZeroCopyStream(&zero_copy_output);
}
bool MessageLite::AppendToString(std::string* output) const {
GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
return AppendPartialToString(output);
@ -474,6 +519,7 @@ void MessageLite::SerializeWithCachedSizes(
output);
}
// The table driven code optimizes the case that the CodedOutputStream buffer
// is large enough to serialize into it directly.
// If the proto is optimized for speed, this method will be overridden by

View File

@ -114,8 +114,8 @@ inline int ToIntSize(size_t size) {
//
// Pay special attention to the initialization state of the object.
// 1. The object is "uninitialized" to begin with.
// 2. Call DefaultConstruct() only if the object is uninitialized.
// After the call, the object becomes "initialized".
// 2. Call Construct() or DefaultConstruct() only if the object is
// uninitialized. After the call, the object becomes "initialized".
// 3. Call get() and get_mutable() only if the object is initialized.
// 4. Call Destruct() only if the object is initialized.
// After the call, the object becomes uninitialized.
@ -124,6 +124,11 @@ class ExplicitlyConstructed {
public:
void DefaultConstruct() { new (&union_) T(); }
template <typename... Args>
void Construct(Args&&... args) {
new (&union_) T(std::forward<Args>(args)...);
}
void Destruct() { get_mutable()->~T(); }
constexpr const T& get() const { return reinterpret_cast<const T&>(union_); }
@ -262,6 +267,18 @@ class PROTOBUF_EXPORT MessageLite {
// Like ParseFromZeroCopyStream(), but accepts messages that are missing
// required fields.
bool ParsePartialFromZeroCopyStream(io::ZeroCopyInputStream* input);
// Parse a protocol buffer from a file descriptor. If successful, the entire
// input will be consumed.
bool ParseFromFileDescriptor(int file_descriptor);
// Like ParseFromFileDescriptor(), but accepts messages that are missing
// required fields.
bool ParsePartialFromFileDescriptor(int file_descriptor);
// Parse a protocol buffer from a C++ istream. If successful, the entire
// input will be consumed.
bool ParseFromIstream(std::istream* input);
// Like ParseFromIstream(), but accepts messages that are missing
// required fields.
bool ParsePartialFromIstream(std::istream* input);
// Read a protocol buffer from the given zero-copy input stream, expecting
// the message to be exactly "size" bytes long. If successful, exactly
// this many bytes will have been consumed from the input.
@ -355,12 +372,24 @@ class PROTOBUF_EXPORT MessageLite {
// Like SerializeAsString(), but allows missing required fields.
std::string SerializePartialAsString() const;
// Serialize the message and write it to the given file descriptor. All
// required fields must be set.
bool SerializeToFileDescriptor(int file_descriptor) const;
// Like SerializeToFileDescriptor(), but allows missing required fields.
bool SerializePartialToFileDescriptor(int file_descriptor) const;
// Serialize the message and write it to the given C++ ostream. All
// required fields must be set.
bool SerializeToOstream(std::ostream* output) const;
// Like SerializeToOstream(), but allows missing required fields.
bool SerializePartialToOstream(std::ostream* output) const;
// Like SerializeToString(), but appends to the data to the string's
// existing contents. All required fields must be set.
bool AppendToString(std::string* output) const;
// Like AppendToString(), but allows missing required fields.
bool AppendPartialToString(std::string* output) const;
// Computes the serialized size of the message. This recursively calls
// ByteSizeLong() on all embedded messages.
//

View File

@ -31,9 +31,9 @@
#ifndef GOOGLE_PROTOBUF_PARSE_CONTEXT_H__
#define GOOGLE_PROTOBUF_PARSE_CONTEXT_H__
#include <cstdint>
#include <cstring>
#include <string>
#include <cstdint>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream.h>

View File

@ -390,16 +390,14 @@ void Struct::SerializeWithCachedSizes(
}
::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());
for (size_type i = 0; i < n; i++) {
Struct_FieldsEntry_DoNotUse::MapEntryWrapper entry(nullptr, items[static_cast<ptrdiff_t>(i)]->first, items[static_cast<ptrdiff_t>(i)]->second);
::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(1, entry, output);
Struct_FieldsEntry_DoNotUse::Funcs::SerializeToCodedStream(1, items[static_cast<ptrdiff_t>(i)]->first, items[static_cast<ptrdiff_t>(i)]->second, output);
Utf8Check::Check(&(*items[static_cast<ptrdiff_t>(i)]));
}
} else {
for (::PROTOBUF_NAMESPACE_ID::Map< std::string, PROTOBUF_NAMESPACE_ID::Value >::const_iterator
it = this->fields().begin();
it != this->fields().end(); ++it) {
Struct_FieldsEntry_DoNotUse::MapEntryWrapper entry(nullptr, it->first, it->second);
::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(1, entry, output);
Struct_FieldsEntry_DoNotUse::Funcs::SerializeToCodedStream(1, it->first, it->second, output);
Utf8Check::Check(&(*it));
}
}
@ -446,16 +444,14 @@ void Struct::SerializeWithCachedSizes(
}
::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());
for (size_type i = 0; i < n; i++) {
Struct_FieldsEntry_DoNotUse::MapEntryWrapper entry(nullptr, items[static_cast<ptrdiff_t>(i)]->first, items[static_cast<ptrdiff_t>(i)]->second);
target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::InternalWriteMessageNoVirtualToArray(1, entry, target);
target = Struct_FieldsEntry_DoNotUse::Funcs::SerializeToArray(1, items[static_cast<ptrdiff_t>(i)]->first, items[static_cast<ptrdiff_t>(i)]->second, target);
Utf8Check::Check(&(*items[static_cast<ptrdiff_t>(i)]));
}
} else {
for (::PROTOBUF_NAMESPACE_ID::Map< std::string, PROTOBUF_NAMESPACE_ID::Value >::const_iterator
it = this->fields().begin();
it != this->fields().end(); ++it) {
Struct_FieldsEntry_DoNotUse::MapEntryWrapper entry(nullptr, it->first, it->second);
target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::InternalWriteMessageNoVirtualToArray(1, entry, target);
target = Struct_FieldsEntry_DoNotUse::Funcs::SerializeToArray(1, it->first, it->second, target);
Utf8Check::Check(&(*it));
}
}
@ -488,9 +484,7 @@ size_t Struct::ByteSizeLong() const {
for (::PROTOBUF_NAMESPACE_ID::Map< std::string, PROTOBUF_NAMESPACE_ID::Value >::const_iterator
it = this->fields().begin();
it != this->fields().end(); ++it) {
Struct_FieldsEntry_DoNotUse::MapEntryWrapper entry(nullptr, it->first, it->second);
total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
MessageSizeNoVirtual(entry);
total_size += Struct_FieldsEntry_DoNotUse::Funcs::ByteSizeLong(it->first, it->second);
}
int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);

View File

@ -174,8 +174,8 @@ message ForeignMessageLite {
enum ForeignEnumLite {
FOREIGN_LITE_FOO = 4;
FOREIGN_LITE_BAR = 5;
FOREIGN_LITE_BAZ = 6;
FOREIGN_LITE_BAR = 5;
}
message TestPackedTypesLite {
@ -473,3 +473,16 @@ message PackedFixed32 {
message NonPackedFixed32 {
repeated fixed32 repeated_fixed32 = 2048;
}
// Test an enum that has multiple values with the same number.
message DupEnum {
enum TestEnumWithDupValueLite {
option allow_alias = true;
FOO1 = 1;
BAR1 = 2;
BAZ = 3;
FOO2 = 1;
BAR2 = 2;
}
}