Merge commit '36bca61764984ff5395653cf8377ec5daa71b709' as 'libs/protobuf'
This commit is contained in:
64
libs/protobuf/src/BUILD.bazel
Normal file
64
libs/protobuf/src/BUILD.bazel
Normal file
@@ -0,0 +1,64 @@
|
||||
################################################################################
|
||||
# Protocol Buffers: C++ Runtime
|
||||
################################################################################
|
||||
|
||||
# Most rules are under google/protobuf. This package exists for convenience.
|
||||
load("@rules_pkg//:mappings.bzl", "pkg_filegroup", "pkg_files", "strip_prefix")
|
||||
load("@upb//cmake:build_defs.bzl", "staleness_test")
|
||||
load("//conformance:defs.bzl", "conformance_test")
|
||||
|
||||
pkg_files(
|
||||
name = "dist_files",
|
||||
srcs = glob(["**"]),
|
||||
strip_prefix = strip_prefix.from_root(""),
|
||||
visibility = ["//src:__pkg__"],
|
||||
)
|
||||
|
||||
pkg_filegroup(
|
||||
name = "all_dist_files",
|
||||
srcs = [
|
||||
":dist_files",
|
||||
"//src/google/protobuf:dist_files",
|
||||
"//src/google/protobuf/compiler:dist_files",
|
||||
"//src/google/protobuf/compiler/cpp:dist_files",
|
||||
"//src/google/protobuf/compiler/csharp:dist_files",
|
||||
"//src/google/protobuf/compiler/java:dist_files",
|
||||
"//src/google/protobuf/compiler/objectivec:dist_files",
|
||||
"//src/google/protobuf/compiler/php:dist_files",
|
||||
"//src/google/protobuf/compiler/python:dist_files",
|
||||
"//src/google/protobuf/compiler/ruby:dist_files",
|
||||
"//src/google/protobuf/io:dist_files",
|
||||
"//src/google/protobuf/stubs:dist_files",
|
||||
"//src/google/protobuf/testing:dist_files",
|
||||
"//src/google/protobuf/util:dist_files",
|
||||
],
|
||||
visibility = ["//pkg:__pkg__"],
|
||||
)
|
||||
|
||||
conformance_test(
|
||||
name = "conformance_test",
|
||||
failure_list = "//conformance:failure_list_cpp.txt",
|
||||
testee = "//conformance:conformance_cpp",
|
||||
text_format_failure_list = "//conformance:text_format_failure_list_cpp.txt",
|
||||
)
|
||||
|
||||
# Copy the generated file_lists.cmake into a place where the staleness test
|
||||
# below can use it.
|
||||
genrule(
|
||||
name = "copy_cmake_lists",
|
||||
srcs = ["//pkg:gen_src_file_lists"],
|
||||
outs = ["cmake_copy/file_lists.cmake"],
|
||||
cmd = "cp $< $@",
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
staleness_test(
|
||||
name = "cmake_lists_staleness_test",
|
||||
outs = ["file_lists.cmake"],
|
||||
generated_pattern = "cmake_copy/%s",
|
||||
# Only run this test if it is explicitly specified on the command line (not
|
||||
# via //src:all or ...). This file will be automatically updated in a
|
||||
# GitHub action, so developers should not worry about failures from this
|
||||
# test.
|
||||
tags = ["manual"],
|
||||
)
|
||||
135
libs/protobuf/src/README.md
Normal file
135
libs/protobuf/src/README.md
Normal file
@@ -0,0 +1,135 @@
|
||||
Protocol Buffers - Google's data interchange format
|
||||
===================================================
|
||||
|
||||
Copyright 2008 Google Inc.
|
||||
|
||||
https://developers.google.com/protocol-buffers/
|
||||
|
||||
CMake Installation
|
||||
-----------------------
|
||||
|
||||
To compile or install protobuf from source using CMake, see
|
||||
[cmake/README.md](../cmake/README.md).
|
||||
|
||||
C++ Protobuf - Unix
|
||||
-----------------------
|
||||
|
||||
To build protobuf from source, the following tools are needed:
|
||||
|
||||
* bazel
|
||||
* git
|
||||
* g++
|
||||
|
||||
On Ubuntu/Debian, for example, you can install them with:
|
||||
|
||||
sudo apt-get install g++ git bazel
|
||||
|
||||
On other platforms, please use the corresponding package managing tool to
|
||||
install them before proceeding. See https://bazel.build/install for further
|
||||
instructions on installing Bazel, or to build from source using CMake, see
|
||||
[cmake/README.md](../cmake/README.md).
|
||||
|
||||
To get the source, download the release .tar.gz or .zip package in the
|
||||
release page:
|
||||
|
||||
https://github.com/protocolbuffers/protobuf/releases/latest
|
||||
|
||||
For example: if you only need C++, download `protobuf-cpp-[VERSION].tar.gz`; if
|
||||
you need C++ and Java, download `protobuf-java-[VERSION].tar.gz` (every package
|
||||
contains C++ source already); if you need C++ and multiple other languages,
|
||||
download `protobuf-all-[VERSION].tar.gz`.
|
||||
|
||||
You can also get the source by "git clone" our git repository. Make sure you
|
||||
have also cloned the submodules and generated the configure script (skip this
|
||||
if you are using a release .tar.gz or .zip package):
|
||||
|
||||
git clone https://github.com/protocolbuffers/protobuf.git
|
||||
cd protobuf
|
||||
git submodule update --init --recursive
|
||||
|
||||
To build the C++ Protocol Buffer runtime and the Protocol Buffer compiler
|
||||
(protoc) execute the following:
|
||||
|
||||
bazel build :protoc :protobuf
|
||||
|
||||
The compiler can then be installed, for example on Linux:
|
||||
|
||||
cp bazel-bin/protoc /usr/local/bin
|
||||
|
||||
For more usage information on Bazel, please refer to http://bazel.build.
|
||||
|
||||
**Compiling dependent packages**
|
||||
|
||||
To compile a package that uses Protocol Buffers, you need to setup a Bazel
|
||||
WORKSPACE that's hooked up to the protobuf repository and loads its
|
||||
dependencies. For an example, see [WORKSPACE](../examples/WORKSPACE).
|
||||
|
||||
**Note for Mac users**
|
||||
|
||||
For a Mac system, Unix tools are not available by default. You will first need
|
||||
to install Xcode from the Mac AppStore and then run the following command from
|
||||
a terminal:
|
||||
|
||||
sudo xcode-select --install
|
||||
|
||||
To install Unix tools, you can install "port" following the instructions at
|
||||
https://www.macports.org . This will reside in /opt/local/bin/port for most
|
||||
Mac installations.
|
||||
|
||||
sudo /opt/local/bin/port install bazel
|
||||
|
||||
Alternative for Homebrew users:
|
||||
|
||||
brew install bazel
|
||||
|
||||
Then follow the Unix instructions above.
|
||||
|
||||
|
||||
C++ Protobuf - Windows
|
||||
--------------------------
|
||||
|
||||
If you only need the protoc binary, you can download it from the release
|
||||
page:
|
||||
|
||||
https://github.com/protocolbuffers/protobuf/releases/latest
|
||||
|
||||
In the downloads section, download the zip file protoc-$VERSION-win32.zip.
|
||||
It contains the protoc binary as well as public proto files of protobuf
|
||||
library.
|
||||
|
||||
Protobuf and its dependencies can be installed directly by using `vcpkg`:
|
||||
|
||||
>vcpkg install protobuf protobuf:x64-windows
|
||||
|
||||
If zlib support is desired, you'll also need to install the zlib feature:
|
||||
|
||||
>vcpkg install protobuf[zlib] protobuf[zlib]:x64-windows
|
||||
|
||||
See https://github.com/Microsoft/vcpkg for more information.
|
||||
|
||||
To build from source using Microsoft Visual C++, see [cmake/README.md](../cmake/README.md).
|
||||
|
||||
To build from source using Cygwin or MinGW, follow the Unix installation
|
||||
instructions, above.
|
||||
|
||||
Binary Compatibility Warning
|
||||
----------------------------
|
||||
|
||||
Due to the nature of C++, it is unlikely that any two versions of the
|
||||
Protocol Buffers C++ runtime libraries will have compatible ABIs.
|
||||
That is, if you linked an executable against an older version of
|
||||
libprotobuf, it is unlikely to work with a newer version without
|
||||
re-compiling. This problem, when it occurs, will normally be detected
|
||||
immediately on startup of your app. Still, you may want to consider
|
||||
using static linkage. You can configure this in your `cc_binary` Bazel rules
|
||||
by specifying:
|
||||
|
||||
linkstatic=True
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
The complete documentation for Protocol Buffers is available via the
|
||||
web at:
|
||||
|
||||
https://developers.google.com/protocol-buffers/
|
||||
732
libs/protobuf/src/file_lists.cmake
Normal file
732
libs/protobuf/src/file_lists.cmake
Normal file
@@ -0,0 +1,732 @@
|
||||
# Auto-generated by //pkg:gen_src_file_lists_cmake
|
||||
#
|
||||
# This file contains lists of sources based on Bazel rules. It should
|
||||
# be included from a hand-written CMake file that defines targets.
|
||||
#
|
||||
# Changes to this file will be overwritten based on Bazel definitions.
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_GREATER 3.10 OR ${CMAKE_VERSION} VERSION_EQUAL 3.10)
|
||||
include_guard()
|
||||
endif()
|
||||
|
||||
# //pkg:protobuf
|
||||
set(libprotobuf_srcs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/any.pb.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/api.pb.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/duration.pb.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/empty.pb.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/field_mask.pb.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/source_context.pb.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/struct.pb.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/timestamp.pb.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/type.pb.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/wrappers.pb.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/any.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/any_lite.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_align.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_config.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arenastring.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arenaz_sampler.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/importer.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/parser.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.pb.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_database.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/dynamic_message.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/extension_set.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/extension_set_heavy.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_enum_util.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_bases.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_reflection.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_tctable_full.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_tctable_gen.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_tctable_lite.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_util.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/implicit_weak_message.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/inlined_string_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/coded_stream.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/gzip_stream.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/io_win32.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/printer.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/strtod.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/tokenizer.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_sink.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/json/internal/lexer.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/message_path.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/parser.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/unparser.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/untyped_message.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/writer.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/zero_copy_buffered_stream.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/json/json.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/message.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/message_lite.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/parse_context.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_ops.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/service.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/structurally_valid.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/strutil.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/text_format.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unknown_field_set.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/delimited_message_util.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_comparator.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_mask_util.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/message_differencer.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/time_util.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/type_resolver_util.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_lite.cc
|
||||
)
|
||||
|
||||
# //pkg:protobuf
|
||||
set(libprotobuf_hdrs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/any.pb.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/api.pb.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/duration.pb.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/empty.pb.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/field_mask.pb.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/source_context.pb.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/struct.pb.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/timestamp.pb.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/type.pb.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/wrappers.pb.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/any.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_align.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_allocation_policy.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_cleanup.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_config.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_impl.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arenastring.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arenaz_sampler.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/importer.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/parser.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.pb.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_database.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/dynamic_message.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/endian.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/explicitly_constructed.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/extension_set.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/extension_set_inl.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/field_access_listener.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_enum_reflection.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_enum_util.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_bases.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_reflection.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_tctable_decl.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_tctable_gen.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_tctable_impl.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_util.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/has_bits.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/implicit_weak_message.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/inlined_string_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/coded_stream.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/gzip_stream.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/io_win32.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/printer.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/strtod.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/tokenizer.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_sink.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/json/internal/descriptor_traits.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/lexer.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/message_path.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/parser.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/parser_traits.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/unparser.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/unparser_traits.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/untyped_message.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/writer.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/zero_copy_buffered_stream.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/json/json.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_entry.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_entry_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_field_inl.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_field_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_type_handler.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/message.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/message_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/metadata.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/metadata_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/parse_context.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/port.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/port_def.inc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/port_undef.inc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/reflection.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_internal.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_ops.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/service.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/common.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/logging.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/mathutil.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/platform_macros.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/port.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/status_macros.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/strutil.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/text_format.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unknown_field_set.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/delimited_message_util.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_comparator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_mask_util.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/json_util.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/message_differencer.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/time_util.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/type_resolver.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/type_resolver_util.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_lite.h
|
||||
)
|
||||
|
||||
# //pkg:protobuf_lite
|
||||
set(libprotobuf_lite_srcs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/any_lite.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_align.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_config.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arenastring.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arenaz_sampler.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_tctable_lite.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_util.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/implicit_weak_message.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/inlined_string_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/coded_stream.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/io_win32.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/map.cc
|
||||
${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/structurally_valid.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/strutil.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_lite.cc
|
||||
)
|
||||
|
||||
# //pkg:protobuf_lite
|
||||
set(libprotobuf_lite_hdrs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/any.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_align.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_allocation_policy.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_cleanup.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_config.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_impl.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arenastring.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arenaz_sampler.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/endian.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/explicitly_constructed.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/extension_set.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/extension_set_inl.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_enum_util.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_tctable_decl.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_tctable_impl.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_util.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/has_bits.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/implicit_weak_message.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/inlined_string_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/coded_stream.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/io_win32.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/map.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_entry_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_field_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_type_handler.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/message_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/metadata_lite.h
|
||||
${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/common.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/logging.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/mathutil.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/platform_macros.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/port.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/status_macros.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/strutil.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_lite.h
|
||||
)
|
||||
|
||||
# //pkg:protoc
|
||||
set(libprotoc_srcs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/code_generator.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/command_line_interface.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/enum.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/enum_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/extension.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/file.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/generator.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/helpers.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/map_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/message.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/message_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/padding_optimizer.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/parse_function_generator.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/primitive_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/service.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/string_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_enum.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_enum_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_field_base.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_generator.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_helpers.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_map_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_message.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_message_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/names.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/context.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/doc_comment.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/enum.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/enum_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/enum_field_lite.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/enum_lite.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/extension.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/extension_lite.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/file.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/generator.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/generator_factory.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/helpers.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/kotlin_generator.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/map_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/map_field_lite.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_builder.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_builder_lite.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_field_lite.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_lite.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_serialization.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/name_resolver.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/names.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/primitive_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/primitive_field_lite.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/service.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/shared_code_generator.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/string_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/string_field_lite.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/enum.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/enum_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/extension.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/file.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/generator.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/helpers.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/import_writer.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/line_consumer.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/map_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/message.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/message_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/names.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/oneof.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/primitive_field.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/text_format_decode_data.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/names.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/php_generator.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.pb.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/generator.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/helpers.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/pyi_generator.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/ruby/ruby_generator.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/subprocess.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/zip_writer.cc
|
||||
)
|
||||
|
||||
# //pkg:protoc
|
||||
set(libprotoc_hdrs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/code_generator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/command_line_interface.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/enum.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/enum_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/extension.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/file.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/generator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/helpers.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/map_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/message.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/message_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/message_layout_helper.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/names.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/options.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/padding_optimizer.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/parse_function_generator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/primitive_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/service.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/string_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_doc_comment.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_enum.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_enum_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_field_base.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_generator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_helpers.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_map_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_message.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_message_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_options.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_primitive_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_reflection_class.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/names.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/context.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/doc_comment.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/enum.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/enum_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/enum_field_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/enum_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/extension.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/extension_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/file.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/generator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/generator_factory.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/helpers.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/kotlin_generator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/map_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/map_field_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_builder.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_builder_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_field_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_serialization.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/name_resolver.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/names.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/options.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/primitive_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/primitive_field_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/service.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/shared_code_generator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/string_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/string_field_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/enum.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/enum_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/extension.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/file.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/generator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/helpers.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/import_writer.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/line_consumer.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/map_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/message.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/message_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/names.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/nsobject_methods.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/oneof.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/options.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/primitive_field.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/text_format_decode_data.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/names.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/php_generator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.pb.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/generator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/helpers.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/pyi_generator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/ruby/ruby_generator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/scc.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/subprocess.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/zip_writer.h
|
||||
)
|
||||
|
||||
# //src/google/protobuf:well_known_type_protos
|
||||
set(wkt_protos_files
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/any.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/api.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/duration.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/empty.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/field_mask.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/source_context.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/struct.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/timestamp.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/type.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/wrappers.proto
|
||||
)
|
||||
|
||||
# //src/google/protobuf:descriptor_proto
|
||||
set(descriptor_proto_proto_srcs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.proto
|
||||
)
|
||||
|
||||
# //src/google/protobuf:descriptor_proto
|
||||
set(descriptor_proto_srcs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.proto.pb.cc
|
||||
)
|
||||
|
||||
# //src/google/protobuf:descriptor_proto
|
||||
set(descriptor_proto_hdrs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.proto.pb.h
|
||||
)
|
||||
|
||||
# //src/google/protobuf:descriptor_proto
|
||||
set(descriptor_proto_files
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_proto-descriptor-set.proto.bin
|
||||
)
|
||||
|
||||
# //src/google/protobuf/compiler:plugin_proto
|
||||
set(plugin_proto_proto_srcs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.proto
|
||||
)
|
||||
|
||||
# //src/google/protobuf/compiler:plugin_proto
|
||||
set(plugin_proto_srcs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.proto.pb.cc
|
||||
)
|
||||
|
||||
# //src/google/protobuf/compiler:plugin_proto
|
||||
set(plugin_proto_hdrs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin.proto.pb.h
|
||||
)
|
||||
|
||||
# //src/google/protobuf/compiler:plugin_proto
|
||||
set(plugin_proto_files
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/plugin_proto-descriptor-set.proto.bin
|
||||
)
|
||||
|
||||
# //pkg:common_test
|
||||
set(common_test_srcs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/mock_code_generator.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/testing/file.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/testing/googletest.cc
|
||||
)
|
||||
|
||||
# //pkg:common_test
|
||||
set(common_test_hdrs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/mock_code_generator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/testing/file.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/testing/googletest.h
|
||||
)
|
||||
|
||||
# //pkg:lite_test_util
|
||||
set(lite_test_util_srcs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_test_util.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_lite_test_util.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/test_util_lite.cc
|
||||
)
|
||||
|
||||
# //pkg:lite_test_util
|
||||
set(lite_test_util_hdrs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_test_util.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_lite_test_util.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_test_util_impl.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/proto3_lite_unittest.inc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/test_util_lite.h
|
||||
)
|
||||
|
||||
# //pkg:test_util
|
||||
set(test_util_srcs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/annotation_test_util.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_tester.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/test_util.cc
|
||||
)
|
||||
|
||||
# //pkg:test_util
|
||||
set(test_util_hdrs
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/annotation_test_util.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/unittest.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/unittest.inc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_test.inc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_test_util.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_test_util.inc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/message_unittest.inc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_tester.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/test_util.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/test_util.inc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/test_util2.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/test_util_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_unittest.inc
|
||||
)
|
||||
|
||||
# //src/google/protobuf:full_test_srcs
|
||||
set(protobuf_test_files
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/any_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_align_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arenastring_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/arenaz_sampler_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_database_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/drop_unknown_fields_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/dynamic_message_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/extension_set_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_reflection_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_tctable_lite_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/inlined_string_field_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_field_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/message_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/no_field_presence_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/preserve_unknown_enum_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/proto3_arena_lite_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/proto3_arena_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/proto3_lite_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_ops_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/repeated_field_reflection_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/repeated_field_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/text_format_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unknown_field_set_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/well_known_types_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_unittest.cc
|
||||
)
|
||||
|
||||
# //src/google/protobuf:test_proto_srcs
|
||||
set(protobuf_test_protos_files
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/any_test.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_proto2_unittest.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_unittest.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_arena.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_custom_options.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_drop_unknown_fields.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_embed_optimize_for.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_empty.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_enormous_descriptor.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_import.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_import_public.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_lazy_dependencies.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_lazy_dependencies_custom_option.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_lazy_dependencies_enum.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_lite_imports_nonlite.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_mset.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_mset_wire_format.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_no_field_presence.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_no_generic_services.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_optimize_for.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_preserve_unknown_enum.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_preserve_unknown_enum2.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_proto3.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_proto3_arena.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_proto3_arena_lite.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_proto3_lite.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_proto3_optional.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_well_known_types.proto
|
||||
)
|
||||
|
||||
# //src/google/protobuf:lite_test_srcs
|
||||
set(protobuf_lite_test_files
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/lite_arena_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/lite_unittest.cc
|
||||
)
|
||||
|
||||
# //src/google/protobuf:lite_test_proto_srcs
|
||||
set(protobuf_lite_test_protos_files
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/map_lite_unittest.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_import_lite.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_import_public_lite.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_lite.proto
|
||||
)
|
||||
|
||||
# //src/google/protobuf/compiler:test_srcs
|
||||
set(compiler_test_files
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/command_line_interface_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/bootstrap_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/message_size_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/metadata_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/move_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/plugin_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/importer_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/doc_comment_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/message_serialization_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/java/plugin_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/line_consumer_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/names_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/objectivec/text_format_decode_data_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/parser_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/plugin_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
|
||||
)
|
||||
|
||||
# //src/google/protobuf/compiler:test_proto_srcs
|
||||
set(compiler_test_protos_files
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/test_bad_identifiers.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
|
||||
)
|
||||
|
||||
# //src/google/protobuf/compiler:test_plugin_srcs
|
||||
set(test_plugin_files
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/test_plugin.cc
|
||||
)
|
||||
|
||||
# //src/google/protobuf/io:test_srcs
|
||||
set(io_test_files
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/coded_stream_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/io_win32_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/printer_death_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/printer_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/tokenizer_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_sink_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_unittest.cc
|
||||
)
|
||||
|
||||
# //src/google/protobuf/util:test_srcs
|
||||
set(util_test_files
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/delimited_message_util_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_comparator_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_mask_util_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/message_differencer_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/time_util_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/type_resolver_util_test.cc
|
||||
)
|
||||
|
||||
# //src/google/protobuf/util:test_proto_srcs
|
||||
set(util_test_protos_files
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/json_format.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/json_format_proto3.proto
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/util/message_differencer_unittest.proto
|
||||
)
|
||||
|
||||
# //src/google/protobuf/stubs:test_srcs
|
||||
set(stubs_test_files
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/bytestream_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/common_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/structurally_valid_unittest.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/strutil_unittest.cc
|
||||
)
|
||||
1291
libs/protobuf/src/google/protobuf/BUILD.bazel
Normal file
1291
libs/protobuf/src/google/protobuf/BUILD.bazel
Normal file
File diff suppressed because it is too large
Load Diff
82
libs/protobuf/src/google/protobuf/any.cc
Normal file
82
libs/protobuf/src/google/protobuf/any.cc
Normal file
@@ -0,0 +1,82 @@
|
||||
// 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/any.h"
|
||||
|
||||
#include "google/protobuf/arenastring.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/generated_message_util.h"
|
||||
#include "google/protobuf/message.h"
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
bool AnyMetadata::PackFrom(Arena* arena, const Message& message) {
|
||||
return PackFrom(arena, message, kTypeGoogleApisComPrefix);
|
||||
}
|
||||
|
||||
bool AnyMetadata::PackFrom(Arena* arena, const Message& message,
|
||||
absl::string_view type_url_prefix) {
|
||||
type_url_->Set(
|
||||
GetTypeUrl(message.GetDescriptor()->full_name(), type_url_prefix), arena);
|
||||
return message.SerializeToString(value_->Mutable(arena));
|
||||
}
|
||||
|
||||
bool AnyMetadata::UnpackTo(Message* message) const {
|
||||
if (!InternalIs(message->GetDescriptor()->full_name())) {
|
||||
return false;
|
||||
}
|
||||
return message->ParseFromString(value_->Get());
|
||||
}
|
||||
|
||||
bool GetAnyFieldDescriptors(const Message& message,
|
||||
const FieldDescriptor** type_url_field,
|
||||
const FieldDescriptor** value_field) {
|
||||
const Descriptor* descriptor = message.GetDescriptor();
|
||||
if (descriptor->full_name() != kAnyFullTypeName) {
|
||||
return false;
|
||||
}
|
||||
*type_url_field = descriptor->FindFieldByNumber(1);
|
||||
*value_field = descriptor->FindFieldByNumber(2);
|
||||
return (*type_url_field != nullptr &&
|
||||
(*type_url_field)->type() == FieldDescriptor::TYPE_STRING &&
|
||||
*value_field != nullptr &&
|
||||
(*value_field)->type() == FieldDescriptor::TYPE_BYTES);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
157
libs/protobuf/src/google/protobuf/any.h
Normal file
157
libs/protobuf/src/google/protobuf/any.h
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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ANY_H__
|
||||
#define GOOGLE_PROTOBUF_ANY_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "google/protobuf/port.h"
|
||||
#include "google/protobuf/arenastring.h"
|
||||
#include "google/protobuf/message_lite.h"
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
class FieldDescriptor;
|
||||
class Message;
|
||||
|
||||
namespace internal {
|
||||
|
||||
extern const char kAnyFullTypeName[]; // "google.protobuf.Any".
|
||||
extern const char kTypeGoogleApisComPrefix[]; // "type.googleapis.com/".
|
||||
extern const char kTypeGoogleProdComPrefix[]; // "type.googleprod.com/".
|
||||
|
||||
std::string GetTypeUrl(absl::string_view message_name,
|
||||
absl::string_view type_url_prefix);
|
||||
|
||||
// Helper class used to implement google::protobuf::Any.
|
||||
class PROTOBUF_EXPORT AnyMetadata {
|
||||
typedef ArenaStringPtr UrlType;
|
||||
typedef ArenaStringPtr ValueType;
|
||||
public:
|
||||
// AnyMetadata does not take ownership of "type_url" and "value".
|
||||
constexpr AnyMetadata(UrlType* type_url, ValueType* value)
|
||||
: type_url_(type_url), value_(value) {}
|
||||
AnyMetadata(const AnyMetadata&) = delete;
|
||||
AnyMetadata& operator=(const AnyMetadata&) = delete;
|
||||
|
||||
// Packs a message using the default type URL prefix: "type.googleapis.com".
|
||||
// The resulted type URL will be "type.googleapis.com/<message_full_name>".
|
||||
// Returns false if serializing the message failed.
|
||||
template <typename T>
|
||||
bool PackFrom(Arena* arena, const T& message) {
|
||||
return InternalPackFrom(arena, message, kTypeGoogleApisComPrefix,
|
||||
T::FullMessageName());
|
||||
}
|
||||
|
||||
bool PackFrom(Arena* arena, const Message& message);
|
||||
|
||||
// Packs a message using the given type URL prefix. The type URL will be
|
||||
// constructed by concatenating the message type's full name to the prefix
|
||||
// with an optional "/" separator if the prefix doesn't already end with "/".
|
||||
// For example, both PackFrom(message, "type.googleapis.com") and
|
||||
// PackFrom(message, "type.googleapis.com/") yield the same result type
|
||||
// URL: "type.googleapis.com/<message_full_name>".
|
||||
// Returns false if serializing the message failed.
|
||||
template <typename T>
|
||||
bool PackFrom(Arena* arena, const T& message,
|
||||
absl::string_view type_url_prefix) {
|
||||
return InternalPackFrom(arena, message, type_url_prefix,
|
||||
T::FullMessageName());
|
||||
}
|
||||
|
||||
bool PackFrom(Arena* arena, const Message& message,
|
||||
absl::string_view type_url_prefix);
|
||||
|
||||
// Unpacks the payload into the given message. Returns false if the message's
|
||||
// type doesn't match the type specified in the type URL (i.e., the full
|
||||
// name after the last "/" of the type URL doesn't match the message's actual
|
||||
// full name) or parsing the payload has failed.
|
||||
template <typename T>
|
||||
bool UnpackTo(T* message) const {
|
||||
return InternalUnpackTo(T::FullMessageName(), message);
|
||||
}
|
||||
|
||||
bool UnpackTo(Message* message) const;
|
||||
|
||||
// Checks whether the type specified in the type URL matches the given type.
|
||||
// A type is considered matching if its full name matches the full name after
|
||||
// the last "/" in the type URL.
|
||||
template <typename T>
|
||||
bool Is() const {
|
||||
return InternalIs(T::FullMessageName());
|
||||
}
|
||||
|
||||
private:
|
||||
bool InternalPackFrom(Arena* arena, const MessageLite& message,
|
||||
absl::string_view type_url_prefix,
|
||||
absl::string_view type_name);
|
||||
bool InternalUnpackTo(absl::string_view type_name,
|
||||
MessageLite* message) const;
|
||||
bool InternalIs(absl::string_view type_name) const;
|
||||
|
||||
UrlType* type_url_;
|
||||
ValueType* value_;
|
||||
};
|
||||
|
||||
// Get the proto type name from Any::type_url value. For example, passing
|
||||
// "type.googleapis.com/rpc.QueryOrigin" will return "rpc.QueryOrigin" in
|
||||
// *full_type_name. Returns false if the type_url does not have a "/"
|
||||
// in the type url separating the full type name.
|
||||
//
|
||||
// NOTE: this function is available publicly as a static method on the
|
||||
// generated message type: google::protobuf::Any::ParseAnyTypeUrl()
|
||||
bool ParseAnyTypeUrl(absl::string_view type_url, std::string* full_type_name);
|
||||
|
||||
// Get the proto type name and prefix from Any::type_url value. For example,
|
||||
// passing "type.googleapis.com/rpc.QueryOrigin" will return
|
||||
// "type.googleapis.com/" in *url_prefix and "rpc.QueryOrigin" in
|
||||
// *full_type_name. Returns false if the type_url does not have a "/" in the
|
||||
// type url separating the full type name.
|
||||
bool ParseAnyTypeUrl(absl::string_view type_url, std::string* url_prefix,
|
||||
std::string* full_type_name);
|
||||
|
||||
// See if message is of type google.protobuf.Any, if so, return the descriptors
|
||||
// for "type_url" and "value" fields.
|
||||
bool GetAnyFieldDescriptors(const Message& message,
|
||||
const FieldDescriptor** type_url_field,
|
||||
const FieldDescriptor** value_field);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ANY_H__
|
||||
395
libs/protobuf/src/google/protobuf/any.pb.cc
Normal file
395
libs/protobuf/src/google/protobuf/any.pb.cc
Normal file
@@ -0,0 +1,395 @@
|
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: google/protobuf/any.proto
|
||||
|
||||
#include "google/protobuf/any.pb.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "google/protobuf/io/coded_stream.h"
|
||||
#include "google/protobuf/extension_set.h"
|
||||
#include "google/protobuf/wire_format_lite.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/generated_message_reflection.h"
|
||||
#include "google/protobuf/reflection_ops.h"
|
||||
#include "google/protobuf/wire_format.h"
|
||||
// @@protoc_insertion_point(includes)
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
PROTOBUF_PRAGMA_INIT_SEG
|
||||
namespace _pb = ::PROTOBUF_NAMESPACE_ID;
|
||||
namespace _pbi = ::PROTOBUF_NAMESPACE_ID::internal;
|
||||
#if defined(__llvm__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wuninitialized"
|
||||
#endif // __llvm__
|
||||
PROTOBUF_NAMESPACE_OPEN
|
||||
PROTOBUF_CONSTEXPR Any::Any(
|
||||
::_pbi::ConstantInitialized): _impl_{
|
||||
/*decltype(_impl_.type_url_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
|
||||
, /*decltype(_impl_.value_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
|
||||
, /*decltype(_impl_._cached_size_)*/{}
|
||||
, /*decltype(_impl_._any_metadata_)*/{&_impl_.type_url_, &_impl_.value_}} {}
|
||||
struct AnyDefaultTypeInternal {
|
||||
PROTOBUF_CONSTEXPR AnyDefaultTypeInternal() : _instance(::_pbi::ConstantInitialized{}) {}
|
||||
~AnyDefaultTypeInternal() {}
|
||||
union {
|
||||
Any _instance;
|
||||
};
|
||||
};
|
||||
|
||||
PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT
|
||||
PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 AnyDefaultTypeInternal _Any_default_instance_;
|
||||
PROTOBUF_NAMESPACE_CLOSE
|
||||
static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fany_2eproto[1];
|
||||
static constexpr const ::_pb::EnumDescriptor**
|
||||
file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto = nullptr;
|
||||
static constexpr const ::_pb::ServiceDescriptor**
|
||||
file_level_service_descriptors_google_2fprotobuf_2fany_2eproto = nullptr;
|
||||
const uint32_t TableStruct_google_2fprotobuf_2fany_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(
|
||||
protodesc_cold) = {
|
||||
~0u, // no _has_bits_
|
||||
PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Any, _internal_metadata_),
|
||||
~0u, // no _extensions_
|
||||
~0u, // no _oneof_case_
|
||||
~0u, // no _weak_field_map_
|
||||
~0u, // no _inlined_string_donated_
|
||||
~0u, // no _split_
|
||||
~0u, // no sizeof(Split)
|
||||
PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Any, _impl_.type_url_),
|
||||
PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Any, _impl_.value_),
|
||||
};
|
||||
|
||||
static const ::_pbi::MigrationSchema
|
||||
schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
|
||||
{ 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Any)},
|
||||
};
|
||||
|
||||
static const ::_pb::Message* const file_default_instances[] = {
|
||||
&::PROTOBUF_NAMESPACE_ID::_Any_default_instance_._instance,
|
||||
};
|
||||
const char descriptor_table_protodef_google_2fprotobuf_2fany_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
|
||||
"\n\031google/protobuf/any.proto\022\017google.prot"
|
||||
"obuf\"&\n\003Any\022\020\n\010type_url\030\001 \001(\t\022\r\n\005value\030\002"
|
||||
" \001(\014Bv\n\023com.google.protobufB\010AnyProtoP\001Z"
|
||||
",google.golang.org/protobuf/types/known/"
|
||||
"anypb\242\002\003GPB\252\002\036Google.Protobuf.WellKnownT"
|
||||
"ypesb\006proto3"
|
||||
};
|
||||
static ::absl::once_flag descriptor_table_google_2fprotobuf_2fany_2eproto_once;
|
||||
const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fany_2eproto = {
|
||||
false,
|
||||
false,
|
||||
212,
|
||||
descriptor_table_protodef_google_2fprotobuf_2fany_2eproto,
|
||||
"google/protobuf/any.proto",
|
||||
&descriptor_table_google_2fprotobuf_2fany_2eproto_once,
|
||||
nullptr,
|
||||
0,
|
||||
1,
|
||||
schemas,
|
||||
file_default_instances,
|
||||
TableStruct_google_2fprotobuf_2fany_2eproto::offsets,
|
||||
file_level_metadata_google_2fprotobuf_2fany_2eproto,
|
||||
file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto,
|
||||
file_level_service_descriptors_google_2fprotobuf_2fany_2eproto,
|
||||
};
|
||||
|
||||
// This function exists to be marked as weak.
|
||||
// It can significantly speed up compilation by breaking up LLVM's SCC
|
||||
// in the .pb.cc translation units. Large translation units see a
|
||||
// reduction of more than 35% of walltime for optimized builds. Without
|
||||
// the weak attribute all the messages in the file, including all the
|
||||
// vtables and everything they use become part of the same SCC through
|
||||
// a cycle like:
|
||||
// GetMetadata -> descriptor table -> default instances ->
|
||||
// vtables -> GetMetadata
|
||||
// By adding a weak function here we break the connection from the
|
||||
// individual vtables back into the descriptor table.
|
||||
PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* descriptor_table_google_2fprotobuf_2fany_2eproto_getter() {
|
||||
return &descriptor_table_google_2fprotobuf_2fany_2eproto;
|
||||
}
|
||||
// Force running AddDescriptors() at dynamic initialization time.
|
||||
PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
|
||||
static ::_pbi::AddDescriptorsRunner dynamic_init_dummy_google_2fprotobuf_2fany_2eproto(&descriptor_table_google_2fprotobuf_2fany_2eproto);
|
||||
PROTOBUF_NAMESPACE_OPEN
|
||||
// ===================================================================
|
||||
|
||||
bool Any::GetAnyFieldDescriptors(
|
||||
const ::PROTOBUF_NAMESPACE_ID::Message& message,
|
||||
const ::PROTOBUF_NAMESPACE_ID::FieldDescriptor** type_url_field,
|
||||
const ::PROTOBUF_NAMESPACE_ID::FieldDescriptor** value_field) {
|
||||
return ::_pbi::GetAnyFieldDescriptors(
|
||||
message, type_url_field, value_field);
|
||||
}
|
||||
bool Any::ParseAnyTypeUrl(
|
||||
::absl::string_view type_url,
|
||||
std::string* full_type_name) {
|
||||
return ::_pbi::ParseAnyTypeUrl(type_url, full_type_name);
|
||||
}
|
||||
|
||||
class Any::_Internal {
|
||||
public:
|
||||
};
|
||||
|
||||
Any::Any(::PROTOBUF_NAMESPACE_ID::Arena* arena,
|
||||
bool is_message_owned)
|
||||
: ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) {
|
||||
SharedCtor(arena, is_message_owned);
|
||||
// @@protoc_insertion_point(arena_constructor:google.protobuf.Any)
|
||||
}
|
||||
Any::Any(const Any& from)
|
||||
: ::PROTOBUF_NAMESPACE_ID::Message() {
|
||||
Any* const _this = this; (void)_this;
|
||||
new (&_impl_) Impl_{
|
||||
decltype(_impl_.type_url_){}
|
||||
, decltype(_impl_.value_){}
|
||||
, /*decltype(_impl_._cached_size_)*/{}
|
||||
, /*decltype(_impl_._any_metadata_)*/{&_impl_.type_url_, &_impl_.value_}};
|
||||
|
||||
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
|
||||
_impl_.type_url_.InitDefault();
|
||||
#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
|
||||
_impl_.type_url_.Set("", GetArenaForAllocation());
|
||||
#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
|
||||
if (!from._internal_type_url().empty()) {
|
||||
_this->_impl_.type_url_.Set(from._internal_type_url(),
|
||||
_this->GetArenaForAllocation());
|
||||
}
|
||||
_impl_.value_.InitDefault();
|
||||
#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
|
||||
_impl_.value_.Set("", GetArenaForAllocation());
|
||||
#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
|
||||
if (!from._internal_value().empty()) {
|
||||
_this->_impl_.value_.Set(from._internal_value(),
|
||||
_this->GetArenaForAllocation());
|
||||
}
|
||||
// @@protoc_insertion_point(copy_constructor:google.protobuf.Any)
|
||||
}
|
||||
|
||||
inline void Any::SharedCtor(
|
||||
::_pb::Arena* arena, bool is_message_owned) {
|
||||
(void)arena;
|
||||
(void)is_message_owned;
|
||||
new (&_impl_) Impl_{
|
||||
decltype(_impl_.type_url_){}
|
||||
, decltype(_impl_.value_){}
|
||||
, /*decltype(_impl_._cached_size_)*/{}
|
||||
, /*decltype(_impl_._any_metadata_)*/{&_impl_.type_url_, &_impl_.value_}
|
||||
};
|
||||
_impl_.type_url_.InitDefault();
|
||||
#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
|
||||
_impl_.type_url_.Set("", GetArenaForAllocation());
|
||||
#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
|
||||
_impl_.value_.InitDefault();
|
||||
#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
|
||||
_impl_.value_.Set("", GetArenaForAllocation());
|
||||
#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
|
||||
}
|
||||
|
||||
Any::~Any() {
|
||||
// @@protoc_insertion_point(destructor:google.protobuf.Any)
|
||||
if (auto *arena = _internal_metadata_.DeleteReturnArena<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>()) {
|
||||
(void)arena;
|
||||
return;
|
||||
}
|
||||
SharedDtor();
|
||||
}
|
||||
|
||||
inline void Any::SharedDtor() {
|
||||
GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
|
||||
_impl_.type_url_.Destroy();
|
||||
_impl_.value_.Destroy();
|
||||
_impl_._any_metadata_.~AnyMetadata();
|
||||
}
|
||||
|
||||
void Any::SetCachedSize(int size) const {
|
||||
_impl_._cached_size_.Set(size);
|
||||
}
|
||||
|
||||
void Any::Clear() {
|
||||
// @@protoc_insertion_point(message_clear_start:google.protobuf.Any)
|
||||
uint32_t cached_has_bits = 0;
|
||||
// Prevent compiler warnings about cached_has_bits being unused
|
||||
(void) cached_has_bits;
|
||||
|
||||
_impl_.type_url_.ClearToEmpty();
|
||||
_impl_.value_.ClearToEmpty();
|
||||
_internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
|
||||
}
|
||||
|
||||
const char* Any::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
|
||||
|
||||
#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
|
||||
while (!ctx->Done(&ptr)) {
|
||||
uint32_t tag;
|
||||
ptr = ::_pbi::ReadTag(ptr, &tag);
|
||||
switch (tag >> 3) {
|
||||
// string type_url = 1;
|
||||
case 1:
|
||||
if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 10)) {
|
||||
auto str = _internal_mutable_type_url();
|
||||
ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
|
||||
CHK_(ptr);
|
||||
CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Any.type_url"));
|
||||
} else
|
||||
goto handle_unusual;
|
||||
continue;
|
||||
// bytes value = 2;
|
||||
case 2:
|
||||
if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 18)) {
|
||||
auto str = _internal_mutable_value();
|
||||
ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
|
||||
CHK_(ptr);
|
||||
} else
|
||||
goto handle_unusual;
|
||||
continue;
|
||||
default:
|
||||
goto handle_unusual;
|
||||
} // switch
|
||||
handle_unusual:
|
||||
if ((tag == 0) || ((tag & 7) == 4)) {
|
||||
CHK_(ptr);
|
||||
ctx->SetLastTag(tag);
|
||||
goto message_done;
|
||||
}
|
||||
ptr = UnknownFieldParse(
|
||||
tag,
|
||||
_internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(),
|
||||
ptr, ctx);
|
||||
CHK_(ptr != nullptr);
|
||||
} // while
|
||||
message_done:
|
||||
return ptr;
|
||||
failure:
|
||||
ptr = nullptr;
|
||||
goto message_done;
|
||||
#undef CHK_
|
||||
}
|
||||
|
||||
uint8_t* Any::_InternalSerialize(
|
||||
uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
|
||||
|
||||
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Any)
|
||||
uint32_t cached_has_bits = 0;
|
||||
(void) cached_has_bits;
|
||||
|
||||
// string type_url = 1;
|
||||
if (!this->_internal_type_url().empty()) {
|
||||
::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
|
||||
this->_internal_type_url().data(), static_cast<int>(this->_internal_type_url().length()),
|
||||
::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
|
||||
"google.protobuf.Any.type_url");
|
||||
target = stream->WriteStringMaybeAliased(
|
||||
1, this->_internal_type_url(), target);
|
||||
}
|
||||
|
||||
// bytes value = 2;
|
||||
if (!this->_internal_value().empty()) {
|
||||
target = stream->WriteBytesMaybeAliased(
|
||||
2, this->_internal_value(), target);
|
||||
}
|
||||
|
||||
if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
|
||||
target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
|
||||
_internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
|
||||
}
|
||||
// @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Any)
|
||||
return target;
|
||||
}
|
||||
|
||||
size_t Any::ByteSizeLong() const {
|
||||
|
||||
// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Any)
|
||||
size_t total_size = 0;
|
||||
|
||||
uint32_t cached_has_bits = 0;
|
||||
// Prevent compiler warnings about cached_has_bits being unused
|
||||
(void) cached_has_bits;
|
||||
|
||||
// string type_url = 1;
|
||||
if (!this->_internal_type_url().empty()) {
|
||||
total_size += 1 +
|
||||
::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
|
||||
this->_internal_type_url());
|
||||
}
|
||||
|
||||
// bytes value = 2;
|
||||
if (!this->_internal_value().empty()) {
|
||||
total_size += 1 +
|
||||
::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::BytesSize(
|
||||
this->_internal_value());
|
||||
}
|
||||
|
||||
return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
|
||||
}
|
||||
|
||||
const ::PROTOBUF_NAMESPACE_ID::Message::ClassData Any::_class_data_ = {
|
||||
::PROTOBUF_NAMESPACE_ID::Message::CopyWithSourceCheck,
|
||||
Any::MergeImpl
|
||||
};
|
||||
const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Any::GetClassData() const { return &_class_data_; }
|
||||
|
||||
|
||||
void Any::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
|
||||
auto* const _this = static_cast<Any*>(&to_msg);
|
||||
auto& from = static_cast<const Any&>(from_msg);
|
||||
|
||||
// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Any)
|
||||
GOOGLE_DCHECK_NE(&from, _this);
|
||||
uint32_t cached_has_bits = 0;
|
||||
(void) cached_has_bits;
|
||||
|
||||
if (!from._internal_type_url().empty()) {
|
||||
_this->_internal_set_type_url(from._internal_type_url());
|
||||
}
|
||||
if (!from._internal_value().empty()) {
|
||||
_this->_internal_set_value(from._internal_value());
|
||||
}
|
||||
_this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
|
||||
}
|
||||
|
||||
void Any::CopyFrom(const Any& from) {
|
||||
// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Any)
|
||||
if (&from == this) return;
|
||||
Clear();
|
||||
MergeFrom(from);
|
||||
}
|
||||
|
||||
bool Any::IsInitialized() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void Any::InternalSwap(Any* other) {
|
||||
using std::swap;
|
||||
auto* lhs_arena = GetArenaForAllocation();
|
||||
auto* rhs_arena = other->GetArenaForAllocation();
|
||||
_internal_metadata_.InternalSwap(&other->_internal_metadata_);
|
||||
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
|
||||
&_impl_.type_url_, lhs_arena,
|
||||
&other->_impl_.type_url_, rhs_arena
|
||||
);
|
||||
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
|
||||
&_impl_.value_, lhs_arena,
|
||||
&other->_impl_.value_, rhs_arena
|
||||
);
|
||||
}
|
||||
|
||||
::PROTOBUF_NAMESPACE_ID::Metadata Any::GetMetadata() const {
|
||||
|
||||
return ::_pbi::AssignDescriptors(
|
||||
&descriptor_table_google_2fprotobuf_2fany_2eproto_getter, &descriptor_table_google_2fprotobuf_2fany_2eproto_once,
|
||||
file_level_metadata_google_2fprotobuf_2fany_2eproto[0]);
|
||||
}
|
||||
// @@protoc_insertion_point(namespace_scope)
|
||||
PROTOBUF_NAMESPACE_CLOSE
|
||||
PROTOBUF_NAMESPACE_OPEN
|
||||
template<> PROTOBUF_NOINLINE ::PROTOBUF_NAMESPACE_ID::Any*
|
||||
Arena::CreateMaybeMessage< ::PROTOBUF_NAMESPACE_ID::Any >(Arena* arena) {
|
||||
return Arena::CreateMessageInternal< ::PROTOBUF_NAMESPACE_ID::Any >(arena);
|
||||
}
|
||||
PROTOBUF_NAMESPACE_CLOSE
|
||||
// @@protoc_insertion_point(global_scope)
|
||||
#if defined(__llvm__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif // __llvm__
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
389
libs/protobuf/src/google/protobuf/any.pb.h
Normal file
389
libs/protobuf/src/google/protobuf/any.pb.h
Normal file
@@ -0,0 +1,389 @@
|
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: google/protobuf/any.proto
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fany_2eproto_2epb_2eh
|
||||
#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fany_2eproto_2epb_2eh
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "google/protobuf/port_def.inc"
|
||||
#if PROTOBUF_VERSION < 3021000
|
||||
#error "This file was generated by a newer version of protoc which is"
|
||||
#error "incompatible with your Protocol Buffer headers. Please update"
|
||||
#error "your headers."
|
||||
#endif // PROTOBUF_VERSION
|
||||
|
||||
#if 3021008 < PROTOBUF_MIN_PROTOC_VERSION
|
||||
#error "This file was generated by an older version of protoc which is"
|
||||
#error "incompatible with your Protocol Buffer headers. Please"
|
||||
#error "regenerate this file with a newer version of protoc."
|
||||
#endif // PROTOBUF_MIN_PROTOC_VERSION
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
#include "google/protobuf/io/coded_stream.h"
|
||||
#include "google/protobuf/arena.h"
|
||||
#include "google/protobuf/arenastring.h"
|
||||
#include "google/protobuf/generated_message_util.h"
|
||||
#include "google/protobuf/metadata_lite.h"
|
||||
#include "google/protobuf/generated_message_reflection.h"
|
||||
#include "google/protobuf/message.h"
|
||||
#include "google/protobuf/repeated_field.h" // IWYU pragma: export
|
||||
#include "google/protobuf/extension_set.h" // IWYU pragma: export
|
||||
#include "google/protobuf/unknown_field_set.h"
|
||||
// @@protoc_insertion_point(includes)
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fany_2eproto PROTOBUF_EXPORT
|
||||
|
||||
PROTOBUF_NAMESPACE_OPEN
|
||||
namespace internal {
|
||||
class AnyMetadata;
|
||||
} // namespace internal
|
||||
PROTOBUF_NAMESPACE_CLOSE
|
||||
|
||||
// Internal implementation detail -- do not use these members.
|
||||
struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2fany_2eproto {
|
||||
static const uint32_t offsets[];
|
||||
};
|
||||
PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable
|
||||
descriptor_table_google_2fprotobuf_2fany_2eproto;
|
||||
PROTOBUF_NAMESPACE_OPEN
|
||||
class Any;
|
||||
struct AnyDefaultTypeInternal;
|
||||
PROTOBUF_EXPORT extern AnyDefaultTypeInternal _Any_default_instance_;
|
||||
template <>
|
||||
PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::Any* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Any>(Arena*);
|
||||
PROTOBUF_NAMESPACE_CLOSE
|
||||
|
||||
PROTOBUF_NAMESPACE_OPEN
|
||||
|
||||
// ===================================================================
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
class PROTOBUF_EXPORT Any final :
|
||||
public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Any) */ {
|
||||
public:
|
||||
inline Any() : Any(nullptr) {}
|
||||
~Any() override;
|
||||
explicit PROTOBUF_CONSTEXPR Any(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
|
||||
|
||||
Any(const Any& from);
|
||||
Any(Any&& from) noexcept
|
||||
: Any() {
|
||||
*this = ::std::move(from);
|
||||
}
|
||||
|
||||
inline Any& operator=(const Any& from) {
|
||||
CopyFrom(from);
|
||||
return *this;
|
||||
}
|
||||
inline Any& operator=(Any&& from) noexcept {
|
||||
if (this == &from) return *this;
|
||||
if (GetOwningArena() == from.GetOwningArena()
|
||||
#ifdef PROTOBUF_FORCE_COPY_IN_MOVE
|
||||
&& GetOwningArena() != nullptr
|
||||
#endif // !PROTOBUF_FORCE_COPY_IN_MOVE
|
||||
) {
|
||||
InternalSwap(&from);
|
||||
} else {
|
||||
CopyFrom(from);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
|
||||
return GetDescriptor();
|
||||
}
|
||||
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
|
||||
return default_instance().GetMetadata().descriptor;
|
||||
}
|
||||
static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
|
||||
return default_instance().GetMetadata().reflection;
|
||||
}
|
||||
static const Any& default_instance() {
|
||||
return *internal_default_instance();
|
||||
}
|
||||
static inline const Any* internal_default_instance() {
|
||||
return reinterpret_cast<const Any*>(
|
||||
&_Any_default_instance_);
|
||||
}
|
||||
static constexpr int kIndexInFileMessages =
|
||||
0;
|
||||
|
||||
// implements Any -----------------------------------------------
|
||||
|
||||
bool PackFrom(const ::PROTOBUF_NAMESPACE_ID::Message& message) {
|
||||
GOOGLE_DCHECK_NE(&message, this);
|
||||
return _impl_._any_metadata_.PackFrom(GetArena(), message);
|
||||
}
|
||||
bool PackFrom(const ::PROTOBUF_NAMESPACE_ID::Message& message,
|
||||
::absl::string_view type_url_prefix) {
|
||||
GOOGLE_DCHECK_NE(&message, this);
|
||||
return _impl_._any_metadata_.PackFrom(GetArena(), message, type_url_prefix);
|
||||
}
|
||||
bool UnpackTo(::PROTOBUF_NAMESPACE_ID::Message* message) const {
|
||||
return _impl_._any_metadata_.UnpackTo(message);
|
||||
}
|
||||
static bool GetAnyFieldDescriptors(
|
||||
const ::PROTOBUF_NAMESPACE_ID::Message& message,
|
||||
const ::PROTOBUF_NAMESPACE_ID::FieldDescriptor** type_url_field,
|
||||
const ::PROTOBUF_NAMESPACE_ID::FieldDescriptor** value_field);
|
||||
template <typename T, class = typename std::enable_if<!std::is_convertible<T, const ::PROTOBUF_NAMESPACE_ID::Message&>::value>::type>
|
||||
bool PackFrom(const T& message) {
|
||||
return _impl_._any_metadata_.PackFrom<T>(GetArena(), message);
|
||||
}
|
||||
template <typename T, class = typename std::enable_if<!std::is_convertible<T, const ::PROTOBUF_NAMESPACE_ID::Message&>::value>::type>
|
||||
bool PackFrom(const T& message,
|
||||
::absl::string_view type_url_prefix) {
|
||||
return _impl_._any_metadata_.PackFrom<T>(GetArena(), message, type_url_prefix);}
|
||||
template <typename T, class = typename std::enable_if<!std::is_convertible<T, const ::PROTOBUF_NAMESPACE_ID::Message&>::value>::type>
|
||||
bool UnpackTo(T* message) const {
|
||||
return _impl_._any_metadata_.UnpackTo<T>(message);
|
||||
}
|
||||
template<typename T> bool Is() const {
|
||||
return _impl_._any_metadata_.Is<T>();
|
||||
}
|
||||
static bool ParseAnyTypeUrl(::absl::string_view type_url,
|
||||
std::string* full_type_name);
|
||||
friend void swap(Any& a, Any& b) {
|
||||
a.Swap(&b);
|
||||
}
|
||||
inline void Swap(Any* other) {
|
||||
if (other == this) return;
|
||||
#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
|
||||
if (GetOwningArena() != nullptr &&
|
||||
GetOwningArena() == other->GetOwningArena()) {
|
||||
#else // PROTOBUF_FORCE_COPY_IN_SWAP
|
||||
if (GetOwningArena() == other->GetOwningArena()) {
|
||||
#endif // !PROTOBUF_FORCE_COPY_IN_SWAP
|
||||
InternalSwap(other);
|
||||
} else {
|
||||
::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
|
||||
}
|
||||
}
|
||||
void UnsafeArenaSwap(Any* other) {
|
||||
if (other == this) return;
|
||||
GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
|
||||
InternalSwap(other);
|
||||
}
|
||||
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
Any* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
|
||||
return CreateMaybeMessage<Any>(arena);
|
||||
}
|
||||
using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
|
||||
void CopyFrom(const Any& from);
|
||||
using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
|
||||
void MergeFrom( const Any& from) {
|
||||
Any::MergeImpl(*this, from);
|
||||
}
|
||||
private:
|
||||
static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg);
|
||||
public:
|
||||
PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
|
||||
bool IsInitialized() const final;
|
||||
|
||||
size_t ByteSizeLong() const final;
|
||||
const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
|
||||
uint8_t* _InternalSerialize(
|
||||
uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
|
||||
int GetCachedSize() const final { return _impl_._cached_size_.Get(); }
|
||||
|
||||
private:
|
||||
void SharedCtor(::PROTOBUF_NAMESPACE_ID::Arena* arena, bool is_message_owned);
|
||||
void SharedDtor();
|
||||
void SetCachedSize(int size) const final;
|
||||
void InternalSwap(Any* other);
|
||||
|
||||
private:
|
||||
friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
|
||||
static ::absl::string_view FullMessageName() {
|
||||
return "google.protobuf.Any";
|
||||
}
|
||||
protected:
|
||||
explicit Any(::PROTOBUF_NAMESPACE_ID::Arena* arena,
|
||||
bool is_message_owned = false);
|
||||
public:
|
||||
|
||||
static const ClassData _class_data_;
|
||||
const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
|
||||
|
||||
::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
|
||||
|
||||
// nested types ----------------------------------------------------
|
||||
|
||||
// accessors -------------------------------------------------------
|
||||
|
||||
enum : int {
|
||||
kTypeUrlFieldNumber = 1,
|
||||
kValueFieldNumber = 2,
|
||||
};
|
||||
// string type_url = 1;
|
||||
void clear_type_url();
|
||||
const std::string& type_url() const;
|
||||
template <typename ArgT0 = const std::string&, typename... ArgT>
|
||||
void set_type_url(ArgT0&& arg0, ArgT... args);
|
||||
std::string* mutable_type_url();
|
||||
PROTOBUF_NODISCARD std::string* release_type_url();
|
||||
void set_allocated_type_url(std::string* type_url);
|
||||
private:
|
||||
const std::string& _internal_type_url() const;
|
||||
inline PROTOBUF_ALWAYS_INLINE void _internal_set_type_url(const std::string& value);
|
||||
std::string* _internal_mutable_type_url();
|
||||
public:
|
||||
|
||||
// bytes value = 2;
|
||||
void clear_value();
|
||||
const std::string& value() const;
|
||||
template <typename ArgT0 = const std::string&, typename... ArgT>
|
||||
void set_value(ArgT0&& arg0, ArgT... args);
|
||||
std::string* mutable_value();
|
||||
PROTOBUF_NODISCARD std::string* release_value();
|
||||
void set_allocated_value(std::string* value);
|
||||
private:
|
||||
const std::string& _internal_value() const;
|
||||
inline PROTOBUF_ALWAYS_INLINE void _internal_set_value(const std::string& value);
|
||||
std::string* _internal_mutable_value();
|
||||
public:
|
||||
|
||||
// @@protoc_insertion_point(class_scope:google.protobuf.Any)
|
||||
private:
|
||||
class _Internal;
|
||||
|
||||
template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
|
||||
typedef void InternalArenaConstructable_;
|
||||
typedef void DestructorSkippable_;
|
||||
struct Impl_ {
|
||||
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr type_url_;
|
||||
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr value_;
|
||||
mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
|
||||
::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata _any_metadata_;
|
||||
};
|
||||
union { Impl_ _impl_; };
|
||||
friend struct ::TableStruct_google_2fprotobuf_2fany_2eproto;
|
||||
};
|
||||
// ===================================================================
|
||||
|
||||
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
#endif // __GNUC__
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// Any
|
||||
|
||||
// string type_url = 1;
|
||||
inline void Any::clear_type_url() {
|
||||
_impl_.type_url_.ClearToEmpty();
|
||||
}
|
||||
inline const std::string& Any::type_url() const {
|
||||
// @@protoc_insertion_point(field_get:google.protobuf.Any.type_url)
|
||||
return _internal_type_url();
|
||||
}
|
||||
template <typename ArgT0, typename... ArgT>
|
||||
inline PROTOBUF_ALWAYS_INLINE
|
||||
void Any::set_type_url(ArgT0&& arg0, ArgT... args) {
|
||||
|
||||
_impl_.type_url_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
|
||||
// @@protoc_insertion_point(field_set:google.protobuf.Any.type_url)
|
||||
}
|
||||
inline std::string* Any::mutable_type_url() {
|
||||
std::string* _s = _internal_mutable_type_url();
|
||||
// @@protoc_insertion_point(field_mutable:google.protobuf.Any.type_url)
|
||||
return _s;
|
||||
}
|
||||
inline const std::string& Any::_internal_type_url() const {
|
||||
return _impl_.type_url_.Get();
|
||||
}
|
||||
inline void Any::_internal_set_type_url(const std::string& value) {
|
||||
|
||||
_impl_.type_url_.Set(value, GetArenaForAllocation());
|
||||
}
|
||||
inline std::string* Any::_internal_mutable_type_url() {
|
||||
|
||||
return _impl_.type_url_.Mutable(GetArenaForAllocation());
|
||||
}
|
||||
inline std::string* Any::release_type_url() {
|
||||
// @@protoc_insertion_point(field_release:google.protobuf.Any.type_url)
|
||||
return _impl_.type_url_.Release();
|
||||
}
|
||||
inline void Any::set_allocated_type_url(std::string* type_url) {
|
||||
_impl_.type_url_.SetAllocated(type_url, GetArenaForAllocation());
|
||||
#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
|
||||
if (_impl_.type_url_.IsDefault()) {
|
||||
_impl_.type_url_.Set("", GetArenaForAllocation());
|
||||
}
|
||||
#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
|
||||
// @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.type_url)
|
||||
}
|
||||
|
||||
// bytes value = 2;
|
||||
inline void Any::clear_value() {
|
||||
_impl_.value_.ClearToEmpty();
|
||||
}
|
||||
inline const std::string& Any::value() const {
|
||||
// @@protoc_insertion_point(field_get:google.protobuf.Any.value)
|
||||
return _internal_value();
|
||||
}
|
||||
template <typename ArgT0, typename... ArgT>
|
||||
inline PROTOBUF_ALWAYS_INLINE
|
||||
void Any::set_value(ArgT0&& arg0, ArgT... args) {
|
||||
|
||||
_impl_.value_.SetBytes(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
|
||||
// @@protoc_insertion_point(field_set:google.protobuf.Any.value)
|
||||
}
|
||||
inline std::string* Any::mutable_value() {
|
||||
std::string* _s = _internal_mutable_value();
|
||||
// @@protoc_insertion_point(field_mutable:google.protobuf.Any.value)
|
||||
return _s;
|
||||
}
|
||||
inline const std::string& Any::_internal_value() const {
|
||||
return _impl_.value_.Get();
|
||||
}
|
||||
inline void Any::_internal_set_value(const std::string& value) {
|
||||
|
||||
_impl_.value_.Set(value, GetArenaForAllocation());
|
||||
}
|
||||
inline std::string* Any::_internal_mutable_value() {
|
||||
|
||||
return _impl_.value_.Mutable(GetArenaForAllocation());
|
||||
}
|
||||
inline std::string* Any::release_value() {
|
||||
// @@protoc_insertion_point(field_release:google.protobuf.Any.value)
|
||||
return _impl_.value_.Release();
|
||||
}
|
||||
inline void Any::set_allocated_value(std::string* value) {
|
||||
_impl_.value_.SetAllocated(value, GetArenaForAllocation());
|
||||
#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
|
||||
if (_impl_.value_.IsDefault()) {
|
||||
_impl_.value_.Set("", GetArenaForAllocation());
|
||||
}
|
||||
#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
|
||||
// @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.value)
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif // __GNUC__
|
||||
|
||||
// @@protoc_insertion_point(namespace_scope)
|
||||
PROTOBUF_NAMESPACE_CLOSE
|
||||
|
||||
|
||||
// @@protoc_insertion_point(global_scope)
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2fany_2eproto_2epb_2eh
|
||||
157
libs/protobuf/src/google/protobuf/any.proto
Normal file
157
libs/protobuf/src/google/protobuf/any.proto
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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option go_package = "google.golang.org/protobuf/types/known/anypb";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "AnyProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
|
||||
// `Any` contains an arbitrary serialized protocol buffer message along with a
|
||||
// URL that describes the type of the serialized message.
|
||||
//
|
||||
// Protobuf library provides support to pack/unpack Any values in the form
|
||||
// of utility functions or additional generated methods of the Any type.
|
||||
//
|
||||
// Example 1: Pack and unpack a message in C++.
|
||||
//
|
||||
// Foo foo = ...;
|
||||
// Any any;
|
||||
// any.PackFrom(foo);
|
||||
// ...
|
||||
// if (any.UnpackTo(&foo)) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// Example 2: Pack and unpack a message in Java.
|
||||
//
|
||||
// Foo foo = ...;
|
||||
// Any any = Any.pack(foo);
|
||||
// ...
|
||||
// if (any.is(Foo.class)) {
|
||||
// foo = any.unpack(Foo.class);
|
||||
// }
|
||||
//
|
||||
// Example 3: Pack and unpack a message in Python.
|
||||
//
|
||||
// foo = Foo(...)
|
||||
// any = Any()
|
||||
// any.Pack(foo)
|
||||
// ...
|
||||
// if any.Is(Foo.DESCRIPTOR):
|
||||
// any.Unpack(foo)
|
||||
// ...
|
||||
//
|
||||
// Example 4: Pack and unpack a message in Go
|
||||
//
|
||||
// foo := &pb.Foo{...}
|
||||
// any, err := anypb.New(foo)
|
||||
// if err != nil {
|
||||
// ...
|
||||
// }
|
||||
// ...
|
||||
// foo := &pb.Foo{}
|
||||
// if err := any.UnmarshalTo(foo); err != nil {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// The pack methods provided by protobuf library will by default use
|
||||
// 'type.googleapis.com/full.type.name' as the type URL and the unpack
|
||||
// methods only use the fully qualified type name after the last '/'
|
||||
// in the type URL, for example "foo.bar.com/x/y.z" will yield type
|
||||
// name "y.z".
|
||||
//
|
||||
// JSON
|
||||
//
|
||||
// The JSON representation of an `Any` value uses the regular
|
||||
// representation of the deserialized, embedded message, with an
|
||||
// additional field `@type` which contains the type URL. Example:
|
||||
//
|
||||
// package google.profile;
|
||||
// message Person {
|
||||
// string first_name = 1;
|
||||
// string last_name = 2;
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// "@type": "type.googleapis.com/google.profile.Person",
|
||||
// "firstName": <string>,
|
||||
// "lastName": <string>
|
||||
// }
|
||||
//
|
||||
// If the embedded message type is well-known and has a custom JSON
|
||||
// representation, that representation will be embedded adding a field
|
||||
// `value` which holds the custom JSON in addition to the `@type`
|
||||
// field. Example (for message [google.protobuf.Duration][]):
|
||||
//
|
||||
// {
|
||||
// "@type": "type.googleapis.com/google.protobuf.Duration",
|
||||
// "value": "1.212s"
|
||||
// }
|
||||
//
|
||||
message Any {
|
||||
// A URL/resource name that uniquely identifies the type of the serialized
|
||||
// protocol buffer message. This string must contain at least
|
||||
// one "/" character. The last segment of the URL's path must represent
|
||||
// the fully qualified name of the type (as in
|
||||
// `path/google.protobuf.Duration`). The name should be in a canonical form
|
||||
// (e.g., leading "." is not accepted).
|
||||
//
|
||||
// In practice, teams usually precompile into the binary all types that they
|
||||
// expect it to use in the context of Any. However, for URLs which use the
|
||||
// scheme `http`, `https`, or no scheme, one can optionally set up a type
|
||||
// server that maps type URLs to message definitions as follows:
|
||||
//
|
||||
// * If no scheme is provided, `https` is assumed.
|
||||
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
|
||||
// value in binary format, or produce an error.
|
||||
// * Applications are allowed to cache lookup results based on the
|
||||
// URL, or have them precompiled into a binary to avoid any
|
||||
// lookup. Therefore, binary compatibility needs to be preserved
|
||||
// on changes to types. (Use versioned type names to manage
|
||||
// breaking changes.)
|
||||
//
|
||||
// Note: this functionality is not currently available in the official
|
||||
// protobuf release, and it is not used for type URLs beginning with
|
||||
// type.googleapis.com.
|
||||
//
|
||||
// Schemes other than `http`, `https` (or the empty scheme) might be
|
||||
// used with implementation specific semantics.
|
||||
//
|
||||
string type_url = 1;
|
||||
|
||||
// Must be a valid serialized protocol buffer of the above specified type.
|
||||
bytes value = 2;
|
||||
}
|
||||
97
libs/protobuf/src/google/protobuf/any_lite.cc
Normal file
97
libs/protobuf/src/google/protobuf/any_lite.cc
Normal file
@@ -0,0 +1,97 @@
|
||||
// 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/io/zero_copy_stream_impl_lite.h"
|
||||
#include "absl/strings/match.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "google/protobuf/any.h"
|
||||
#include "google/protobuf/arenastring.h"
|
||||
#include "google/protobuf/generated_message_util.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
std::string GetTypeUrl(absl::string_view message_name,
|
||||
absl::string_view type_url_prefix) {
|
||||
if (!type_url_prefix.empty() &&
|
||||
type_url_prefix[type_url_prefix.size() - 1] == '/') {
|
||||
return absl::StrCat(type_url_prefix, message_name);
|
||||
} else {
|
||||
return absl::StrCat(type_url_prefix, "/", message_name);
|
||||
}
|
||||
}
|
||||
|
||||
const char kAnyFullTypeName[] = "google.protobuf.Any";
|
||||
const char kTypeGoogleApisComPrefix[] = "type.googleapis.com/";
|
||||
const char kTypeGoogleProdComPrefix[] = "type.googleprod.com/";
|
||||
|
||||
bool AnyMetadata::InternalPackFrom(Arena* arena, const MessageLite& message,
|
||||
absl::string_view type_url_prefix,
|
||||
absl::string_view type_name) {
|
||||
type_url_->Set(GetTypeUrl(type_name, type_url_prefix), arena);
|
||||
return message.SerializeToString(value_->Mutable(arena));
|
||||
}
|
||||
|
||||
bool AnyMetadata::InternalUnpackTo(absl::string_view type_name,
|
||||
MessageLite* message) const {
|
||||
if (!InternalIs(type_name)) {
|
||||
return false;
|
||||
}
|
||||
return message->ParseFromString(value_->Get());
|
||||
}
|
||||
|
||||
bool AnyMetadata::InternalIs(absl::string_view type_name) const {
|
||||
absl::string_view type_url = type_url_->Get();
|
||||
return type_url.size() >= type_name.size() + 1 &&
|
||||
type_url[type_url.size() - type_name.size() - 1] == '/' &&
|
||||
absl::EndsWith(type_url, type_name);
|
||||
}
|
||||
|
||||
bool ParseAnyTypeUrl(absl::string_view type_url, std::string* url_prefix,
|
||||
std::string* full_type_name) {
|
||||
size_t pos = type_url.find_last_of('/');
|
||||
if (pos == std::string::npos || pos + 1 == type_url.size()) {
|
||||
return false;
|
||||
}
|
||||
if (url_prefix) {
|
||||
*url_prefix = std::string(type_url.substr(0, pos + 1));
|
||||
}
|
||||
*full_type_name = std::string(type_url.substr(pos + 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseAnyTypeUrl(absl::string_view type_url, std::string* full_type_name) {
|
||||
return ParseAnyTypeUrl(type_url, nullptr, full_type_name);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
195
libs/protobuf/src/google/protobuf/any_test.cc
Normal file
195
libs/protobuf/src/google/protobuf/any_test.cc
Normal file
@@ -0,0 +1,195 @@
|
||||
// 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/any_test.pb.h"
|
||||
#include "google/protobuf/unittest.pb.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include "absl/strings/str_cat.h"
|
||||
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace {
|
||||
|
||||
TEST(AnyMetadataTest, ConstInit) {
|
||||
PROTOBUF_CONSTINIT static internal::AnyMetadata metadata(nullptr, nullptr);
|
||||
(void)metadata;
|
||||
}
|
||||
|
||||
TEST(AnyTest, TestPackAndUnpack) {
|
||||
protobuf_unittest::TestAny submessage;
|
||||
submessage.set_int32_value(12345);
|
||||
protobuf_unittest::TestAny message;
|
||||
ASSERT_TRUE(message.mutable_any_value()->PackFrom(submessage));
|
||||
|
||||
std::string data = message.SerializeAsString();
|
||||
|
||||
ASSERT_TRUE(message.ParseFromString(data));
|
||||
EXPECT_TRUE(message.has_any_value());
|
||||
submessage.Clear();
|
||||
ASSERT_TRUE(message.any_value().UnpackTo(&submessage));
|
||||
EXPECT_EQ(12345, submessage.int32_value());
|
||||
}
|
||||
|
||||
TEST(AnyTest, TestPackFromSerializationExceedsSizeLimit) {
|
||||
protobuf_unittest::TestAny submessage;
|
||||
submessage.mutable_text()->resize(INT_MAX, 'a');
|
||||
protobuf_unittest::TestAny message;
|
||||
EXPECT_FALSE(message.mutable_any_value()->PackFrom(submessage));
|
||||
}
|
||||
|
||||
TEST(AnyTest, TestUnpackWithTypeMismatch) {
|
||||
protobuf_unittest::TestAny payload;
|
||||
payload.set_int32_value(13);
|
||||
google::protobuf::Any any;
|
||||
any.PackFrom(payload);
|
||||
|
||||
// Attempt to unpack into the wrong type.
|
||||
protobuf_unittest::TestAllTypes dest;
|
||||
EXPECT_FALSE(any.UnpackTo(&dest));
|
||||
}
|
||||
|
||||
TEST(AnyTest, TestPackAndUnpackAny) {
|
||||
// We can pack a Any message inside another Any message.
|
||||
protobuf_unittest::TestAny submessage;
|
||||
submessage.set_int32_value(12345);
|
||||
google::protobuf::Any any;
|
||||
any.PackFrom(submessage);
|
||||
protobuf_unittest::TestAny message;
|
||||
message.mutable_any_value()->PackFrom(any);
|
||||
|
||||
std::string data = message.SerializeAsString();
|
||||
|
||||
ASSERT_TRUE(message.ParseFromString(data));
|
||||
EXPECT_TRUE(message.has_any_value());
|
||||
any.Clear();
|
||||
submessage.Clear();
|
||||
ASSERT_TRUE(message.any_value().UnpackTo(&any));
|
||||
ASSERT_TRUE(any.UnpackTo(&submessage));
|
||||
EXPECT_EQ(12345, submessage.int32_value());
|
||||
}
|
||||
|
||||
TEST(AnyTest, TestPackWithCustomTypeUrl) {
|
||||
protobuf_unittest::TestAny submessage;
|
||||
submessage.set_int32_value(12345);
|
||||
google::protobuf::Any any;
|
||||
// Pack with a custom type URL prefix.
|
||||
any.PackFrom(submessage, "type.myservice.com");
|
||||
EXPECT_EQ("type.myservice.com/protobuf_unittest.TestAny", any.type_url());
|
||||
// Pack with a custom type URL prefix ending with '/'.
|
||||
any.PackFrom(submessage, "type.myservice.com/");
|
||||
EXPECT_EQ("type.myservice.com/protobuf_unittest.TestAny", any.type_url());
|
||||
// Pack with an empty type URL prefix.
|
||||
any.PackFrom(submessage, "");
|
||||
EXPECT_EQ("/protobuf_unittest.TestAny", any.type_url());
|
||||
|
||||
// Test unpacking the type.
|
||||
submessage.Clear();
|
||||
EXPECT_TRUE(any.UnpackTo(&submessage));
|
||||
EXPECT_EQ(12345, submessage.int32_value());
|
||||
}
|
||||
|
||||
TEST(AnyTest, TestIs) {
|
||||
protobuf_unittest::TestAny submessage;
|
||||
submessage.set_int32_value(12345);
|
||||
google::protobuf::Any any;
|
||||
any.PackFrom(submessage);
|
||||
ASSERT_TRUE(any.ParseFromString(any.SerializeAsString()));
|
||||
EXPECT_TRUE(any.Is<protobuf_unittest::TestAny>());
|
||||
EXPECT_FALSE(any.Is<google::protobuf::Any>());
|
||||
|
||||
protobuf_unittest::TestAny message;
|
||||
message.mutable_any_value()->PackFrom(any);
|
||||
ASSERT_TRUE(message.ParseFromString(message.SerializeAsString()));
|
||||
EXPECT_FALSE(message.any_value().Is<protobuf_unittest::TestAny>());
|
||||
EXPECT_TRUE(message.any_value().Is<google::protobuf::Any>());
|
||||
|
||||
any.set_type_url("/protobuf_unittest.TestAny");
|
||||
EXPECT_TRUE(any.Is<protobuf_unittest::TestAny>());
|
||||
// The type URL must contain at least one "/".
|
||||
any.set_type_url("protobuf_unittest.TestAny");
|
||||
EXPECT_FALSE(any.Is<protobuf_unittest::TestAny>());
|
||||
// The type name after the slash must be fully qualified.
|
||||
any.set_type_url("/TestAny");
|
||||
EXPECT_FALSE(any.Is<protobuf_unittest::TestAny>());
|
||||
}
|
||||
|
||||
TEST(AnyTest, MoveConstructor) {
|
||||
protobuf_unittest::TestAny payload;
|
||||
payload.set_int32_value(12345);
|
||||
|
||||
google::protobuf::Any src;
|
||||
src.PackFrom(payload);
|
||||
|
||||
const char* type_url = src.type_url().data();
|
||||
|
||||
google::protobuf::Any dst(std::move(src));
|
||||
EXPECT_EQ(type_url, dst.type_url().data());
|
||||
payload.Clear();
|
||||
ASSERT_TRUE(dst.UnpackTo(&payload));
|
||||
EXPECT_EQ(12345, payload.int32_value());
|
||||
}
|
||||
|
||||
TEST(AnyTest, MoveAssignment) {
|
||||
protobuf_unittest::TestAny payload;
|
||||
payload.set_int32_value(12345);
|
||||
|
||||
google::protobuf::Any src;
|
||||
src.PackFrom(payload);
|
||||
|
||||
const char* type_url = src.type_url().data();
|
||||
|
||||
google::protobuf::Any dst;
|
||||
dst = std::move(src);
|
||||
EXPECT_EQ(type_url, dst.type_url().data());
|
||||
payload.Clear();
|
||||
ASSERT_TRUE(dst.UnpackTo(&payload));
|
||||
EXPECT_EQ(12345, payload.int32_value());
|
||||
}
|
||||
|
||||
#ifdef PROTOBUF_HAS_DEATH_TEST
|
||||
#ifndef NDEBUG
|
||||
TEST(AnyTest, PackSelfDeath) {
|
||||
google::protobuf::Any any;
|
||||
EXPECT_DEATH(any.PackFrom(any), "&message");
|
||||
EXPECT_DEATH(any.PackFrom(any, ""), "&message");
|
||||
}
|
||||
#endif // !NDEBUG
|
||||
#endif // PROTOBUF_HAS_DEATH_TEST
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
44
libs/protobuf/src/google/protobuf/any_test.proto
Normal file
44
libs/protobuf/src/google/protobuf/any_test.proto
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package protobuf_unittest;
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
|
||||
option java_outer_classname = "TestAnyProto";
|
||||
|
||||
message TestAny {
|
||||
int32 int32_value = 1;
|
||||
google.protobuf.Any any_value = 2;
|
||||
repeated google.protobuf.Any repeated_any_value = 3;
|
||||
string text = 4;
|
||||
}
|
||||
1351
libs/protobuf/src/google/protobuf/api.pb.cc
Normal file
1351
libs/protobuf/src/google/protobuf/api.pb.cc
Normal file
File diff suppressed because it is too large
Load Diff
1408
libs/protobuf/src/google/protobuf/api.pb.h
Normal file
1408
libs/protobuf/src/google/protobuf/api.pb.h
Normal file
File diff suppressed because it is too large
Load Diff
207
libs/protobuf/src/google/protobuf/api.proto
Normal file
207
libs/protobuf/src/google/protobuf/api.proto
Normal file
@@ -0,0 +1,207 @@
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
import "google/protobuf/source_context.proto";
|
||||
import "google/protobuf/type.proto";
|
||||
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "ApiProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
option go_package = "google.golang.org/protobuf/types/known/apipb";
|
||||
|
||||
// Api is a light-weight descriptor for an API Interface.
|
||||
//
|
||||
// Interfaces are also described as "protocol buffer services" in some contexts,
|
||||
// such as by the "service" keyword in a .proto file, but they are different
|
||||
// from API Services, which represent a concrete implementation of an interface
|
||||
// as opposed to simply a description of methods and bindings. They are also
|
||||
// sometimes simply referred to as "APIs" in other contexts, such as the name of
|
||||
// this message itself. See https://cloud.google.com/apis/design/glossary for
|
||||
// detailed terminology.
|
||||
message Api {
|
||||
// The fully qualified name of this interface, including package name
|
||||
// followed by the interface's simple name.
|
||||
string name = 1;
|
||||
|
||||
// The methods of this interface, in unspecified order.
|
||||
repeated Method methods = 2;
|
||||
|
||||
// Any metadata attached to the interface.
|
||||
repeated Option options = 3;
|
||||
|
||||
// A version string for this interface. If specified, must have the form
|
||||
// `major-version.minor-version`, as in `1.10`. If the minor version is
|
||||
// omitted, it defaults to zero. If the entire version field is empty, the
|
||||
// major version is derived from the package name, as outlined below. If the
|
||||
// field is not empty, the version in the package name will be verified to be
|
||||
// consistent with what is provided here.
|
||||
//
|
||||
// The versioning schema uses [semantic
|
||||
// versioning](http://semver.org) where the major version number
|
||||
// indicates a breaking change and the minor version an additive,
|
||||
// non-breaking change. Both version numbers are signals to users
|
||||
// what to expect from different versions, and should be carefully
|
||||
// chosen based on the product plan.
|
||||
//
|
||||
// The major version is also reflected in the package name of the
|
||||
// interface, which must end in `v<major-version>`, as in
|
||||
// `google.feature.v1`. For major versions 0 and 1, the suffix can
|
||||
// be omitted. Zero major versions must only be used for
|
||||
// experimental, non-GA interfaces.
|
||||
//
|
||||
string version = 4;
|
||||
|
||||
// Source context for the protocol buffer service represented by this
|
||||
// message.
|
||||
SourceContext source_context = 5;
|
||||
|
||||
// Included interfaces. See [Mixin][].
|
||||
repeated Mixin mixins = 6;
|
||||
|
||||
// The source syntax of the service.
|
||||
Syntax syntax = 7;
|
||||
}
|
||||
|
||||
// Method represents a method of an API interface.
|
||||
message Method {
|
||||
// The simple name of this method.
|
||||
string name = 1;
|
||||
|
||||
// A URL of the input message type.
|
||||
string request_type_url = 2;
|
||||
|
||||
// If true, the request is streamed.
|
||||
bool request_streaming = 3;
|
||||
|
||||
// The URL of the output message type.
|
||||
string response_type_url = 4;
|
||||
|
||||
// If true, the response is streamed.
|
||||
bool response_streaming = 5;
|
||||
|
||||
// Any metadata attached to the method.
|
||||
repeated Option options = 6;
|
||||
|
||||
// The source syntax of this method.
|
||||
Syntax syntax = 7;
|
||||
}
|
||||
|
||||
// Declares an API Interface to be included in this interface. The including
|
||||
// interface must redeclare all the methods from the included interface, but
|
||||
// documentation and options are inherited as follows:
|
||||
//
|
||||
// - If after comment and whitespace stripping, the documentation
|
||||
// string of the redeclared method is empty, it will be inherited
|
||||
// from the original method.
|
||||
//
|
||||
// - Each annotation belonging to the service config (http,
|
||||
// visibility) which is not set in the redeclared method will be
|
||||
// inherited.
|
||||
//
|
||||
// - If an http annotation is inherited, the path pattern will be
|
||||
// modified as follows. Any version prefix will be replaced by the
|
||||
// version of the including interface plus the [root][] path if
|
||||
// specified.
|
||||
//
|
||||
// Example of a simple mixin:
|
||||
//
|
||||
// package google.acl.v1;
|
||||
// service AccessControl {
|
||||
// // Get the underlying ACL object.
|
||||
// rpc GetAcl(GetAclRequest) returns (Acl) {
|
||||
// option (google.api.http).get = "/v1/{resource=**}:getAcl";
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// package google.storage.v2;
|
||||
// service Storage {
|
||||
// rpc GetAcl(GetAclRequest) returns (Acl);
|
||||
//
|
||||
// // Get a data record.
|
||||
// rpc GetData(GetDataRequest) returns (Data) {
|
||||
// option (google.api.http).get = "/v2/{resource=**}";
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Example of a mixin configuration:
|
||||
//
|
||||
// apis:
|
||||
// - name: google.storage.v2.Storage
|
||||
// mixins:
|
||||
// - name: google.acl.v1.AccessControl
|
||||
//
|
||||
// The mixin construct implies that all methods in `AccessControl` are
|
||||
// also declared with same name and request/response types in
|
||||
// `Storage`. A documentation generator or annotation processor will
|
||||
// see the effective `Storage.GetAcl` method after inheriting
|
||||
// documentation and annotations as follows:
|
||||
//
|
||||
// service Storage {
|
||||
// // Get the underlying ACL object.
|
||||
// rpc GetAcl(GetAclRequest) returns (Acl) {
|
||||
// option (google.api.http).get = "/v2/{resource=**}:getAcl";
|
||||
// }
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// Note how the version in the path pattern changed from `v1` to `v2`.
|
||||
//
|
||||
// If the `root` field in the mixin is specified, it should be a
|
||||
// relative path under which inherited HTTP paths are placed. Example:
|
||||
//
|
||||
// apis:
|
||||
// - name: google.storage.v2.Storage
|
||||
// mixins:
|
||||
// - name: google.acl.v1.AccessControl
|
||||
// root: acls
|
||||
//
|
||||
// This implies the following inherited HTTP annotation:
|
||||
//
|
||||
// service Storage {
|
||||
// // Get the underlying ACL object.
|
||||
// rpc GetAcl(GetAclRequest) returns (Acl) {
|
||||
// option (google.api.http).get = "/v2/acls/{resource=**}:getAcl";
|
||||
// }
|
||||
// ...
|
||||
// }
|
||||
message Mixin {
|
||||
// The fully qualified name of the interface which is included.
|
||||
string name = 1;
|
||||
|
||||
// If non-empty specifies a path under which inherited HTTP paths
|
||||
// are rooted.
|
||||
string root = 2;
|
||||
}
|
||||
901
libs/protobuf/src/google/protobuf/arena.cc
Normal file
901
libs/protobuf/src/google/protobuf/arena.cc
Normal file
@@ -0,0 +1,901 @@
|
||||
// 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/arena.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "google/protobuf/arena_allocation_policy.h"
|
||||
#include "google/protobuf/arena_impl.h"
|
||||
#include "google/protobuf/arenaz_sampler.h"
|
||||
#include "google/protobuf/port.h"
|
||||
|
||||
|
||||
#ifdef ADDRESS_SANITIZER
|
||||
#include <sanitizer/asan_interface.h>
|
||||
#endif // ADDRESS_SANITIZER
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 5
|
||||
// kSentryArenaBlock is used for arenas which can be referenced pre-main. So,
|
||||
// constexpr is required.
|
||||
constexpr ArenaBlock kSentryArenaBlock;
|
||||
|
||||
ArenaBlock* SentryArenaBlock() {
|
||||
// const_cast<> is okay as kSentryArenaBlock will never be mutated.
|
||||
return const_cast<ArenaBlock*>(&kSentryArenaBlock);
|
||||
}
|
||||
#else
|
||||
// TODO(b/248322260) Remove this once we're not using GCC 4.9 for tests.
|
||||
// There is a compiler bug in this version that causes the above constexpr to
|
||||
// fail. This version is no longer in our support window, but we use it in
|
||||
// some of our aarch64 docker images.
|
||||
ArenaBlock* SentryArenaBlock() {
|
||||
static const ArenaBlock kSentryArenaBlock;
|
||||
// const_cast<> is okay as kSentryArenaBlock will never be mutated.
|
||||
return const_cast<ArenaBlock*>(&kSentryArenaBlock);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
static SerialArena::Memory AllocateMemory(const AllocationPolicy* policy_ptr,
|
||||
size_t last_size, size_t min_bytes) {
|
||||
AllocationPolicy policy; // default policy
|
||||
if (policy_ptr) policy = *policy_ptr;
|
||||
size_t size;
|
||||
if (last_size != 0) {
|
||||
// Double the current block size, up to a limit.
|
||||
auto max_size = policy.max_block_size;
|
||||
size = std::min(2 * last_size, max_size);
|
||||
} else {
|
||||
size = policy.start_block_size;
|
||||
}
|
||||
// Verify that min_bytes + kBlockHeaderSize won't overflow.
|
||||
GOOGLE_CHECK_LE(min_bytes,
|
||||
std::numeric_limits<size_t>::max() - SerialArena::kBlockHeaderSize);
|
||||
size = std::max(size, SerialArena::kBlockHeaderSize + min_bytes);
|
||||
|
||||
void* mem;
|
||||
if (policy.block_alloc == nullptr) {
|
||||
mem = ::operator new(size);
|
||||
} else {
|
||||
mem = policy.block_alloc(size);
|
||||
}
|
||||
return {mem, size};
|
||||
}
|
||||
|
||||
class GetDeallocator {
|
||||
public:
|
||||
GetDeallocator(const AllocationPolicy* policy, size_t* space_allocated)
|
||||
: dealloc_(policy ? policy->block_dealloc : nullptr),
|
||||
space_allocated_(space_allocated) {}
|
||||
|
||||
void operator()(SerialArena::Memory mem) const {
|
||||
#ifdef ADDRESS_SANITIZER
|
||||
// This memory was provided by the underlying allocator as unpoisoned,
|
||||
// so return it in an unpoisoned state.
|
||||
ASAN_UNPOISON_MEMORY_REGION(mem.ptr, mem.size);
|
||||
#endif // ADDRESS_SANITIZER
|
||||
if (dealloc_) {
|
||||
dealloc_(mem.ptr, mem.size);
|
||||
} else {
|
||||
internal::SizedDelete(mem.ptr, mem.size);
|
||||
}
|
||||
*space_allocated_ += mem.size;
|
||||
}
|
||||
|
||||
private:
|
||||
void (*dealloc_)(void*, size_t);
|
||||
size_t* space_allocated_;
|
||||
};
|
||||
|
||||
// It is guaranteed that this is constructed in `b`. IOW, this is not the first
|
||||
// arena and `b` cannot be sentry.
|
||||
SerialArena::SerialArena(ArenaBlock* b, ThreadSafeArena& parent)
|
||||
: ptr_{b->Pointer(kBlockHeaderSize + ThreadSafeArena::kSerialArenaSize)},
|
||||
limit_{b->Limit()},
|
||||
head_{b},
|
||||
space_allocated_{b->size},
|
||||
parent_{parent} {
|
||||
GOOGLE_DCHECK(!b->IsSentry());
|
||||
}
|
||||
|
||||
// It is guaranteed that this is the first SerialArena. Use sentry block.
|
||||
SerialArena::SerialArena(ThreadSafeArena& parent)
|
||||
: head_{SentryArenaBlock()}, parent_{parent} {}
|
||||
|
||||
// It is guaranteed that this is the first SerialArena but `b` may be user
|
||||
// provided or newly allocated to store AllocationPolicy.
|
||||
SerialArena::SerialArena(FirstSerialArena, ArenaBlock* b,
|
||||
ThreadSafeArena& parent)
|
||||
: head_{b}, space_allocated_{b->size}, parent_{parent} {
|
||||
if (b->IsSentry()) return;
|
||||
|
||||
set_ptr(b->Pointer(kBlockHeaderSize));
|
||||
limit_ = b->Limit();
|
||||
}
|
||||
|
||||
void SerialArena::Init(ArenaBlock* b, size_t offset) {
|
||||
set_ptr(b->Pointer(offset));
|
||||
limit_ = b->Limit();
|
||||
head_.store(b, std::memory_order_relaxed);
|
||||
space_used_.store(0, std::memory_order_relaxed);
|
||||
space_allocated_.store(b->size, std::memory_order_relaxed);
|
||||
cached_block_length_ = 0;
|
||||
cached_blocks_ = nullptr;
|
||||
}
|
||||
|
||||
SerialArena* SerialArena::New(Memory mem, ThreadSafeArena& parent) {
|
||||
GOOGLE_DCHECK_LE(kBlockHeaderSize + ThreadSafeArena::kSerialArenaSize, mem.size);
|
||||
ThreadSafeArenaStats::RecordAllocateStats(parent.arena_stats_.MutableStats(),
|
||||
/*used=*/0, /*allocated=*/mem.size,
|
||||
/*wasted=*/0);
|
||||
auto b = new (mem.ptr) ArenaBlock{nullptr, mem.size};
|
||||
return new (b->Pointer(kBlockHeaderSize)) SerialArena(b, parent);
|
||||
}
|
||||
|
||||
template <typename Deallocator>
|
||||
SerialArena::Memory SerialArena::Free(Deallocator deallocator) {
|
||||
ArenaBlock* b = head();
|
||||
Memory mem = {b, b->size};
|
||||
while (b->next) {
|
||||
b = b->next; // We must first advance before deleting this block
|
||||
deallocator(mem);
|
||||
mem = {b, b->size};
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
PROTOBUF_NOINLINE
|
||||
void* SerialArena::AllocateAlignedFallback(size_t n) {
|
||||
AllocateNewBlock(n);
|
||||
return AllocateFromExisting(n);
|
||||
}
|
||||
|
||||
PROTOBUF_NOINLINE
|
||||
void* SerialArena::AllocateAlignedWithCleanupFallback(
|
||||
size_t n, size_t align, void (*destructor)(void*)) {
|
||||
size_t required = AlignUpTo(n, align) + cleanup::Size(destructor);
|
||||
AllocateNewBlock(required);
|
||||
return AllocateFromExistingWithCleanupFallback(n, align, destructor);
|
||||
}
|
||||
|
||||
PROTOBUF_NOINLINE
|
||||
void SerialArena::AddCleanupFallback(void* elem, void (*destructor)(void*)) {
|
||||
size_t required = cleanup::Size(destructor);
|
||||
AllocateNewBlock(required);
|
||||
AddCleanupFromExisting(elem, destructor);
|
||||
}
|
||||
|
||||
void SerialArena::AllocateNewBlock(size_t n) {
|
||||
size_t used = 0;
|
||||
size_t wasted = 0;
|
||||
ArenaBlock* old_head = head();
|
||||
if (!old_head->IsSentry()) {
|
||||
// Sync limit to block
|
||||
old_head->cleanup_nodes = limit_;
|
||||
|
||||
// Record how much used in this block.
|
||||
used = static_cast<size_t>(ptr() - old_head->Pointer(kBlockHeaderSize));
|
||||
wasted = old_head->size - used;
|
||||
space_used_.store(space_used_.load(std::memory_order_relaxed) + used,
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
// TODO(sbenza): Evaluate if pushing unused space into the cached blocks is a
|
||||
// win. In preliminary testing showed increased memory savings as expected,
|
||||
// but with a CPU regression. The regression might have been an artifact of
|
||||
// the microbenchmark.
|
||||
|
||||
auto mem = AllocateMemory(parent_.AllocPolicy(), old_head->size, n);
|
||||
// We don't want to emit an expensive RMW instruction that requires
|
||||
// exclusive access to a cacheline. Hence we write it in terms of a
|
||||
// regular add.
|
||||
space_allocated_.store(
|
||||
space_allocated_.load(std::memory_order_relaxed) + mem.size,
|
||||
std::memory_order_relaxed);
|
||||
ThreadSafeArenaStats::RecordAllocateStats(parent_.arena_stats_.MutableStats(),
|
||||
/*used=*/used,
|
||||
/*allocated=*/mem.size, wasted);
|
||||
auto* new_head = new (mem.ptr) ArenaBlock{old_head, mem.size};
|
||||
set_ptr(new_head->Pointer(kBlockHeaderSize));
|
||||
limit_ = new_head->Limit();
|
||||
// Previous writes must take effect before writing new head.
|
||||
head_.store(new_head, std::memory_order_release);
|
||||
|
||||
#ifdef ADDRESS_SANITIZER
|
||||
ASAN_POISON_MEMORY_REGION(ptr(), limit_ - ptr());
|
||||
#endif // ADDRESS_SANITIZER
|
||||
}
|
||||
|
||||
uint64_t SerialArena::SpaceUsed() const {
|
||||
// Note: the calculation below technically causes a race with
|
||||
// AllocateNewBlock when called from another thread (which happens in
|
||||
// ThreadSafeArena::SpaceUsed). However, worst-case space_used_ will have
|
||||
// stale data and the calculation will incorrectly assume 100%
|
||||
// usage of the *current* block.
|
||||
// TODO(mkruskal) Consider eliminating this race in exchange for a possible
|
||||
// performance hit on ARM (see cl/455186837).
|
||||
const ArenaBlock* h = head_.load(std::memory_order_acquire);
|
||||
if (h->IsSentry()) return 0;
|
||||
|
||||
const uint64_t current_block_size = h->size;
|
||||
uint64_t current_space_used = std::min(
|
||||
static_cast<uint64_t>(
|
||||
ptr() - const_cast<ArenaBlock*>(h)->Pointer(kBlockHeaderSize)),
|
||||
current_block_size);
|
||||
return current_space_used + space_used_.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void SerialArena::CleanupList() {
|
||||
ArenaBlock* b = head();
|
||||
if (b->IsSentry()) return;
|
||||
|
||||
b->cleanup_nodes = limit_;
|
||||
do {
|
||||
char* limit = b->Limit();
|
||||
char* it = reinterpret_cast<char*>(b->cleanup_nodes);
|
||||
GOOGLE_DCHECK(!b->IsSentry() || it == limit);
|
||||
if (it < limit) {
|
||||
// A prefetch distance of 8 here was chosen arbitrarily. It makes the
|
||||
// pending nodes fill a cacheline which seemed nice.
|
||||
constexpr int kPrefetchDist = 8;
|
||||
cleanup::Tag pending_type[kPrefetchDist];
|
||||
char* pending_node[kPrefetchDist];
|
||||
|
||||
int pos = 0;
|
||||
for (; pos < kPrefetchDist && it < limit; ++pos) {
|
||||
pending_type[pos] = cleanup::Type(it);
|
||||
pending_node[pos] = it;
|
||||
it += cleanup::Size(pending_type[pos]);
|
||||
}
|
||||
|
||||
if (pos < kPrefetchDist) {
|
||||
for (int i = 0; i < pos; ++i) {
|
||||
cleanup::DestroyNode(pending_type[i], pending_node[i]);
|
||||
}
|
||||
} else {
|
||||
pos = 0;
|
||||
while (it < limit) {
|
||||
cleanup::PrefetchNode(it);
|
||||
cleanup::DestroyNode(pending_type[pos], pending_node[pos]);
|
||||
pending_type[pos] = cleanup::Type(it);
|
||||
pending_node[pos] = it;
|
||||
it += cleanup::Size(pending_type[pos]);
|
||||
pos = (pos + 1) % kPrefetchDist;
|
||||
}
|
||||
for (int i = pos; i < pos + kPrefetchDist; ++i) {
|
||||
cleanup::DestroyNode(pending_type[i % kPrefetchDist],
|
||||
pending_node[i % kPrefetchDist]);
|
||||
}
|
||||
}
|
||||
}
|
||||
b = b->next;
|
||||
} while (b);
|
||||
}
|
||||
|
||||
// Stores arrays of void* and SerialArena* instead of linked list of
|
||||
// SerialArena* to speed up traversing all SerialArena. The cost of walk is non
|
||||
// trivial when there are many nodes. Separately storing "ids" minimizes cache
|
||||
// footprints and more efficient when looking for matching arena.
|
||||
//
|
||||
// Uses absl::container_internal::Layout to emulate the following:
|
||||
//
|
||||
// struct SerialArenaChunk {
|
||||
// struct SerialArenaChunkHeader {
|
||||
// SerialArenaChunk* next_chunk;
|
||||
// uint32_t capacity;
|
||||
// std::atomic<uint32_t> size;
|
||||
// } header;
|
||||
// std::atomic<void*> ids[];
|
||||
// std::atomic<SerialArena*> arenas[];
|
||||
// };
|
||||
//
|
||||
// where the size of "ids" and "arenas" is determined at runtime; hence the use
|
||||
// of Layout.
|
||||
struct SerialArenaChunkHeader {
|
||||
constexpr SerialArenaChunkHeader(uint32_t capacity, uint32_t size)
|
||||
: next_chunk(nullptr), capacity(capacity), size(size) {}
|
||||
|
||||
ThreadSafeArena::SerialArenaChunk* next_chunk;
|
||||
uint32_t capacity;
|
||||
std::atomic<uint32_t> size;
|
||||
};
|
||||
|
||||
class ThreadSafeArena::SerialArenaChunk {
|
||||
public:
|
||||
SerialArenaChunk(uint32_t capacity, void* me, SerialArena* serial) {
|
||||
new (&header()) SerialArenaChunkHeader{capacity, 1};
|
||||
|
||||
new (&id(0)) std::atomic<void*>{me};
|
||||
for (uint32_t i = 1; i < capacity; ++i) {
|
||||
new (&id(i)) std::atomic<void*>{nullptr};
|
||||
}
|
||||
|
||||
new (&arena(0)) std::atomic<SerialArena*>{serial};
|
||||
for (uint32_t i = 1; i < capacity; ++i) {
|
||||
new (&arena(i)) std::atomic<void*>{nullptr};
|
||||
}
|
||||
}
|
||||
|
||||
bool IsSentry() const { return capacity() == 0; }
|
||||
|
||||
// next_chunk
|
||||
const SerialArenaChunk* next_chunk() const { return header().next_chunk; }
|
||||
SerialArenaChunk* next_chunk() { return header().next_chunk; }
|
||||
void set_next(SerialArenaChunk* next_chunk) {
|
||||
header().next_chunk = next_chunk;
|
||||
}
|
||||
|
||||
// capacity
|
||||
uint32_t capacity() const { return header().capacity; }
|
||||
void set_capacity(uint32_t capacity) { header().capacity = capacity; }
|
||||
|
||||
// ids: returns up to size().
|
||||
absl::Span<const std::atomic<void*>> ids() const {
|
||||
return Layout(capacity()).Slice<kIds>(ptr()).first(safe_size());
|
||||
}
|
||||
absl::Span<std::atomic<void*>> ids() {
|
||||
return Layout(capacity()).Slice<kIds>(ptr()).first(safe_size());
|
||||
}
|
||||
std::atomic<void*>& id(uint32_t i) {
|
||||
GOOGLE_DCHECK_LT(i, capacity());
|
||||
return Layout(capacity()).Pointer<kIds>(ptr())[i];
|
||||
}
|
||||
|
||||
// arenas: returns up to size().
|
||||
absl::Span<const std::atomic<SerialArena*>> arenas() const {
|
||||
return Layout(capacity()).Slice<kArenas>(ptr()).first(safe_size());
|
||||
}
|
||||
absl::Span<std::atomic<SerialArena*>> arenas() {
|
||||
return Layout(capacity()).Slice<kArenas>(ptr()).first(safe_size());
|
||||
}
|
||||
const std::atomic<SerialArena*>& arena(uint32_t i) const {
|
||||
GOOGLE_DCHECK_LT(i, capacity());
|
||||
return Layout(capacity()).Pointer<kArenas>(ptr())[i];
|
||||
}
|
||||
std::atomic<SerialArena*>& arena(uint32_t i) {
|
||||
GOOGLE_DCHECK_LT(i, capacity());
|
||||
return Layout(capacity()).Pointer<kArenas>(ptr())[i];
|
||||
}
|
||||
|
||||
// Tries to insert {id, serial} to head chunk. Returns false if the head is
|
||||
// already full.
|
||||
//
|
||||
// Note that the updating "size", "id", "arena" is individually atomic but
|
||||
// those are not protected by a mutex. This is acceptable because concurrent
|
||||
// lookups from SpaceUsed or SpaceAllocated accept inaccuracy due to race. On
|
||||
// other paths, either race is not possible (GetSerialArenaFallback) or must
|
||||
// be prevented by users (CleanupList, Free).
|
||||
bool insert(void* me, SerialArena* serial) {
|
||||
uint32_t idx = size().fetch_add(1, std::memory_order_relaxed);
|
||||
// Bail out if this chunk is full.
|
||||
if (idx >= capacity()) {
|
||||
// Write old value back to avoid potential overflow.
|
||||
size().store(capacity(), std::memory_order_relaxed);
|
||||
return false;
|
||||
}
|
||||
|
||||
id(idx).store(me, std::memory_order_relaxed);
|
||||
arena(idx).store(serial, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr static size_t AllocSize(size_t n) { return Layout(n).AllocSize(); }
|
||||
|
||||
private:
|
||||
constexpr static int kHeader = 0;
|
||||
constexpr static int kIds = 1;
|
||||
constexpr static int kArenas = 2;
|
||||
|
||||
using layout_type = absl::container_internal::Layout<
|
||||
SerialArenaChunkHeader, std::atomic<void*>, std::atomic<SerialArena*>>;
|
||||
|
||||
const char* ptr() const { return reinterpret_cast<const char*>(this); }
|
||||
char* ptr() { return reinterpret_cast<char*>(this); }
|
||||
|
||||
SerialArenaChunkHeader& header() {
|
||||
return *layout_type::Partial().Pointer<kHeader>(ptr());
|
||||
}
|
||||
const SerialArenaChunkHeader& header() const {
|
||||
return *layout_type::Partial().Pointer<kHeader>(ptr());
|
||||
}
|
||||
|
||||
std::atomic<uint32_t>& size() { return header().size; }
|
||||
const std::atomic<uint32_t>& size() const { return header().size; }
|
||||
|
||||
// Returns the size capped by the capacity as fetch_add may result in a size
|
||||
// greater than capacity.
|
||||
uint32_t safe_size() const {
|
||||
return std::min(capacity(), size().load(std::memory_order_relaxed));
|
||||
}
|
||||
|
||||
constexpr static layout_type Layout(size_t n) {
|
||||
return layout_type(
|
||||
/*header*/ 1,
|
||||
/*ids*/ n,
|
||||
/*arenas*/ n);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr SerialArenaChunkHeader kSentryArenaChunk = {0, 0};
|
||||
|
||||
ThreadSafeArena::SerialArenaChunk* ThreadSafeArena::SentrySerialArenaChunk() {
|
||||
// const_cast is okay because the sentry chunk is never mutated. Also,
|
||||
// reinterpret_cast is acceptable here as it should be identical to
|
||||
// SerialArenaChunk with zero payload. This is a necessary trick to
|
||||
// constexpr initialize kSentryArenaChunk.
|
||||
return reinterpret_cast<SerialArenaChunk*>(
|
||||
const_cast<SerialArenaChunkHeader*>(&kSentryArenaChunk));
|
||||
}
|
||||
|
||||
|
||||
ThreadSafeArena::CacheAlignedLifecycleIdGenerator
|
||||
ThreadSafeArena::lifecycle_id_generator_;
|
||||
#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
|
||||
ThreadSafeArena::ThreadCache& ThreadSafeArena::thread_cache() {
|
||||
static internal::ThreadLocalStorage<ThreadCache>* thread_cache_ =
|
||||
new internal::ThreadLocalStorage<ThreadCache>();
|
||||
return *thread_cache_->Get();
|
||||
}
|
||||
#elif defined(PROTOBUF_USE_DLLS)
|
||||
ThreadSafeArena::ThreadCache& ThreadSafeArena::thread_cache() {
|
||||
static PROTOBUF_THREAD_LOCAL ThreadCache thread_cache_ = {
|
||||
0, static_cast<LifecycleIdAtomic>(-1), nullptr};
|
||||
return thread_cache_;
|
||||
}
|
||||
#else
|
||||
PROTOBUF_THREAD_LOCAL ThreadSafeArena::ThreadCache
|
||||
ThreadSafeArena::thread_cache_ = {0, static_cast<LifecycleIdAtomic>(-1),
|
||||
nullptr};
|
||||
#endif
|
||||
|
||||
ThreadSafeArena::ThreadSafeArena() : first_arena_(*this) { Init(); }
|
||||
|
||||
// Constructor solely used by message-owned arena.
|
||||
ThreadSafeArena::ThreadSafeArena(internal::MessageOwned)
|
||||
: tag_and_id_(kMessageOwnedArena), first_arena_(*this) {
|
||||
Init();
|
||||
}
|
||||
|
||||
ThreadSafeArena::ThreadSafeArena(char* mem, size_t size)
|
||||
: first_arena_(FirstSerialArena{}, FirstBlock(mem, size), *this) {
|
||||
Init();
|
||||
}
|
||||
|
||||
ThreadSafeArena::ThreadSafeArena(void* mem, size_t size,
|
||||
const AllocationPolicy& policy)
|
||||
: first_arena_(FirstSerialArena{}, FirstBlock(mem, size, policy), *this) {
|
||||
InitializeWithPolicy(policy);
|
||||
}
|
||||
|
||||
ArenaBlock* ThreadSafeArena::FirstBlock(void* buf, size_t size) {
|
||||
GOOGLE_DCHECK_EQ(reinterpret_cast<uintptr_t>(buf) & 7, 0u);
|
||||
if (buf == nullptr || size <= kBlockHeaderSize) {
|
||||
return SentryArenaBlock();
|
||||
}
|
||||
// Record user-owned block.
|
||||
alloc_policy_.set_is_user_owned_initial_block(true);
|
||||
return new (buf) ArenaBlock{nullptr, size};
|
||||
}
|
||||
|
||||
ArenaBlock* ThreadSafeArena::FirstBlock(void* buf, size_t size,
|
||||
const AllocationPolicy& policy) {
|
||||
if (policy.IsDefault()) return FirstBlock(buf, size);
|
||||
|
||||
GOOGLE_DCHECK_EQ(reinterpret_cast<uintptr_t>(buf) & 7, 0u);
|
||||
|
||||
SerialArena::Memory mem;
|
||||
if (buf == nullptr || size < kBlockHeaderSize + kAllocPolicySize) {
|
||||
mem = AllocateMemory(&policy, 0, kAllocPolicySize);
|
||||
} else {
|
||||
mem = {buf, size};
|
||||
// Record user-owned block.
|
||||
alloc_policy_.set_is_user_owned_initial_block(true);
|
||||
}
|
||||
|
||||
return new (mem.ptr) ArenaBlock{nullptr, mem.size};
|
||||
}
|
||||
|
||||
void ThreadSafeArena::InitializeWithPolicy(const AllocationPolicy& policy) {
|
||||
Init();
|
||||
|
||||
if (policy.IsDefault()) return;
|
||||
|
||||
#ifndef NDEBUG
|
||||
const uint64_t old_alloc_policy = alloc_policy_.get_raw();
|
||||
// If there was a policy (e.g., in Reset()), make sure flags were preserved.
|
||||
#define GOOGLE_DCHECK_POLICY_FLAGS_() \
|
||||
if (old_alloc_policy > 3) \
|
||||
GOOGLE_CHECK_EQ(old_alloc_policy & 3, alloc_policy_.get_raw() & 3)
|
||||
#else
|
||||
#define GOOGLE_DCHECK_POLICY_FLAGS_()
|
||||
#endif // NDEBUG
|
||||
|
||||
// We ensured enough space so this cannot fail.
|
||||
void* p;
|
||||
if (!first_arena_.MaybeAllocateAligned(kAllocPolicySize, &p)) {
|
||||
GOOGLE_LOG(FATAL) << "MaybeAllocateAligned cannot fail here.";
|
||||
return;
|
||||
}
|
||||
new (p) AllocationPolicy{policy};
|
||||
// Low bits store flags, so they mustn't be overwritten.
|
||||
GOOGLE_DCHECK_EQ(0, reinterpret_cast<uintptr_t>(p) & 3);
|
||||
alloc_policy_.set_policy(reinterpret_cast<AllocationPolicy*>(p));
|
||||
GOOGLE_DCHECK_POLICY_FLAGS_();
|
||||
|
||||
#undef GOOGLE_DCHECK_POLICY_FLAGS_
|
||||
}
|
||||
|
||||
uint64_t ThreadSafeArena::GetNextLifeCycleId() {
|
||||
ThreadCache& tc = thread_cache();
|
||||
uint64_t id = tc.next_lifecycle_id;
|
||||
// We increment lifecycle_id's by multiples of two so we can use bit 0 as
|
||||
// a tag.
|
||||
constexpr uint64_t kDelta = 2;
|
||||
constexpr uint64_t kInc = ThreadCache::kPerThreadIds * kDelta;
|
||||
if (PROTOBUF_PREDICT_FALSE((id & (kInc - 1)) == 0)) {
|
||||
// On platforms that don't support uint64_t atomics we can certainly not
|
||||
// afford to increment by large intervals and expect uniqueness due to
|
||||
// wrapping, hence we only add by 1.
|
||||
id = lifecycle_id_generator_.id.fetch_add(1, std::memory_order_relaxed) *
|
||||
kInc;
|
||||
}
|
||||
tc.next_lifecycle_id = id + kDelta;
|
||||
return id;
|
||||
}
|
||||
|
||||
// We assume that #threads / arena is bimodal; i.e. majority small ones are
|
||||
// single threaded but some big ones are highly concurrent. To balance between
|
||||
// memory overhead and minimum pointer chasing, we start with few entries and
|
||||
// exponentially (4x) grow with a limit (255 entries). Note that parameters are
|
||||
// picked for x64 architectures as hint and the actual size is calculated by
|
||||
// Layout.
|
||||
ThreadSafeArena::SerialArenaChunk* ThreadSafeArena::NewSerialArenaChunk(
|
||||
uint32_t prev_capacity, void* id, SerialArena* serial) {
|
||||
constexpr size_t kMaxBytes = 4096; // Can hold up to 255 entries.
|
||||
constexpr size_t kGrowthFactor = 4;
|
||||
constexpr size_t kHeaderSize = SerialArenaChunk::AllocSize(0);
|
||||
constexpr size_t kEntrySize = SerialArenaChunk::AllocSize(1) - kHeaderSize;
|
||||
|
||||
// On x64 arch: {4, 16, 64, 256, 256, ...} * 16.
|
||||
size_t prev_bytes = SerialArenaChunk::AllocSize(prev_capacity);
|
||||
size_t next_bytes = std::min(kMaxBytes, prev_bytes * kGrowthFactor);
|
||||
uint32_t next_capacity =
|
||||
static_cast<uint32_t>(next_bytes - kHeaderSize) / kEntrySize;
|
||||
// Growth based on bytes needs to be adjusted by AllocSize.
|
||||
next_bytes = SerialArenaChunk::AllocSize(next_capacity);
|
||||
void* mem;
|
||||
mem = ::operator new(next_bytes);
|
||||
|
||||
return new (mem) SerialArenaChunk{next_capacity, id, serial};
|
||||
}
|
||||
|
||||
// Tries to reserve an entry by atomic fetch_add. If the head chunk is already
|
||||
// full (size >= capacity), acquires the mutex and adds a new head.
|
||||
void ThreadSafeArena::AddSerialArena(void* id, SerialArena* serial) {
|
||||
SerialArenaChunk* head = head_.load(std::memory_order_acquire);
|
||||
// Fast path without acquiring mutex.
|
||||
if (!head->IsSentry() && head->insert(id, serial)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Slow path with acquiring mutex.
|
||||
absl::MutexLock lock(&mutex_);
|
||||
|
||||
// Refetch and if someone else installed a new head, try allocating on that!
|
||||
SerialArenaChunk* new_head = head_.load(std::memory_order_acquire);
|
||||
if (new_head != head) {
|
||||
if (new_head->insert(id, serial)) return;
|
||||
// Update head to link to the latest one.
|
||||
head = new_head;
|
||||
}
|
||||
|
||||
new_head = NewSerialArenaChunk(head->capacity(), id, serial);
|
||||
new_head->set_next(head);
|
||||
|
||||
// Use "std::memory_order_release" to make sure prior stores are visible after
|
||||
// this one.
|
||||
head_.store(new_head, std::memory_order_release);
|
||||
}
|
||||
|
||||
void ThreadSafeArena::Init() {
|
||||
const bool message_owned = IsMessageOwned();
|
||||
if (!message_owned) {
|
||||
// Message-owned arenas bypass thread cache and do not need life cycle ID.
|
||||
tag_and_id_ = GetNextLifeCycleId();
|
||||
} else {
|
||||
GOOGLE_DCHECK_EQ(tag_and_id_, kMessageOwnedArena);
|
||||
}
|
||||
arena_stats_ = Sample();
|
||||
head_.store(SentrySerialArenaChunk(), std::memory_order_relaxed);
|
||||
GOOGLE_DCHECK_EQ(message_owned, IsMessageOwned());
|
||||
first_owner_ = &thread_cache();
|
||||
|
||||
// Record allocation for the first block that was either user-provided or
|
||||
// newly allocated.
|
||||
ThreadSafeArenaStats::RecordAllocateStats(
|
||||
arena_stats_.MutableStats(),
|
||||
/*used=*/0,
|
||||
/*allocated=*/first_arena_.SpaceAllocated(),
|
||||
/*wasted=*/0);
|
||||
|
||||
CacheSerialArena(&first_arena_);
|
||||
}
|
||||
|
||||
ThreadSafeArena::~ThreadSafeArena() {
|
||||
// Have to do this in a first pass, because some of the destructors might
|
||||
// refer to memory in other blocks.
|
||||
CleanupList();
|
||||
|
||||
size_t space_allocated = 0;
|
||||
auto mem = Free(&space_allocated);
|
||||
if (alloc_policy_.is_user_owned_initial_block()) {
|
||||
#ifdef ADDRESS_SANITIZER
|
||||
// Unpoison the initial block, now that it's going back to the user.
|
||||
ASAN_UNPOISON_MEMORY_REGION(mem.ptr, mem.size);
|
||||
#endif // ADDRESS_SANITIZER
|
||||
space_allocated += mem.size;
|
||||
} else if (mem.size > 0) {
|
||||
GetDeallocator(alloc_policy_.get(), &space_allocated)(mem);
|
||||
}
|
||||
}
|
||||
|
||||
SerialArena::Memory ThreadSafeArena::Free(size_t* space_allocated) {
|
||||
auto deallocator = GetDeallocator(alloc_policy_.get(), space_allocated);
|
||||
|
||||
WalkSerialArenaChunk([deallocator](SerialArenaChunk* chunk) {
|
||||
absl::Span<std::atomic<SerialArena*>> span = chunk->arenas();
|
||||
// Walks arenas backward to handle the first serial arena the last. Freeing
|
||||
// in reverse-order to the order in which objects were created may not be
|
||||
// necessary to Free and we should revisit this. (b/247560530)
|
||||
for (auto it = span.rbegin(); it != span.rend(); ++it) {
|
||||
SerialArena* serial = it->load(std::memory_order_relaxed);
|
||||
GOOGLE_DCHECK_NE(serial, nullptr);
|
||||
// Always frees the first block of "serial" as it cannot be user-provided.
|
||||
SerialArena::Memory mem = serial->Free(deallocator);
|
||||
GOOGLE_DCHECK_NE(mem.ptr, nullptr);
|
||||
deallocator(mem);
|
||||
}
|
||||
|
||||
// Delete the chunk as we're done with it.
|
||||
internal::SizedDelete(chunk,
|
||||
SerialArenaChunk::AllocSize(chunk->capacity()));
|
||||
});
|
||||
|
||||
// The first block of the first arena is special and let the caller handle it.
|
||||
return first_arena_.Free(deallocator);
|
||||
}
|
||||
|
||||
uint64_t ThreadSafeArena::Reset() {
|
||||
// Have to do this in a first pass, because some of the destructors might
|
||||
// refer to memory in other blocks.
|
||||
CleanupList();
|
||||
|
||||
// Discard all blocks except the first one. Whether it is user-provided or
|
||||
// allocated, always reuse the first block for the first arena.
|
||||
size_t space_allocated = 0;
|
||||
auto mem = Free(&space_allocated);
|
||||
space_allocated += mem.size;
|
||||
|
||||
// Reset the first arena with the first block. This avoids redundant
|
||||
// free / allocation and re-allocating for AllocationPolicy. Adjust offset if
|
||||
// we need to preserve alloc_policy_.
|
||||
if (alloc_policy_.is_user_owned_initial_block() ||
|
||||
alloc_policy_.get() != nullptr) {
|
||||
size_t offset = alloc_policy_.get() == nullptr
|
||||
? kBlockHeaderSize
|
||||
: kBlockHeaderSize + kAllocPolicySize;
|
||||
first_arena_.Init(new (mem.ptr) ArenaBlock{nullptr, mem.size}, offset);
|
||||
} else {
|
||||
first_arena_.Init(SentryArenaBlock(), 0);
|
||||
}
|
||||
|
||||
// Since the first block and potential alloc_policy on the first block is
|
||||
// preserved, this can be initialized by Init().
|
||||
Init();
|
||||
|
||||
return space_allocated;
|
||||
}
|
||||
|
||||
void* ThreadSafeArena::AllocateAlignedWithCleanup(size_t n, size_t align,
|
||||
void (*destructor)(void*)) {
|
||||
SerialArena* arena;
|
||||
if (PROTOBUF_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
|
||||
return arena->AllocateAlignedWithCleanup(n, align, destructor);
|
||||
} else {
|
||||
return AllocateAlignedWithCleanupFallback(n, align, destructor);
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadSafeArena::AddCleanup(void* elem, void (*cleanup)(void*)) {
|
||||
SerialArena* arena;
|
||||
if (PROTOBUF_PREDICT_FALSE(!GetSerialArenaFast(&arena))) {
|
||||
arena = GetSerialArenaFallback(kMaxCleanupNodeSize);
|
||||
}
|
||||
arena->AddCleanup(elem, cleanup);
|
||||
}
|
||||
|
||||
PROTOBUF_NOINLINE
|
||||
void* ThreadSafeArena::AllocateAlignedWithCleanupFallback(
|
||||
size_t n, size_t align, void (*destructor)(void*)) {
|
||||
return GetSerialArenaFallback(n + kMaxCleanupNodeSize)
|
||||
->AllocateAlignedWithCleanup(n, align, destructor);
|
||||
}
|
||||
|
||||
template <typename Functor>
|
||||
void ThreadSafeArena::WalkConstSerialArenaChunk(Functor fn) const {
|
||||
const SerialArenaChunk* chunk = head_.load(std::memory_order_acquire);
|
||||
|
||||
for (; !chunk->IsSentry(); chunk = chunk->next_chunk()) {
|
||||
fn(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Functor>
|
||||
void ThreadSafeArena::WalkSerialArenaChunk(Functor fn) {
|
||||
// By omitting an Acquire barrier we help the sanitizer that any user code
|
||||
// that doesn't properly synchronize Reset() or the destructor will throw a
|
||||
// TSAN warning.
|
||||
SerialArenaChunk* chunk = head_.load(std::memory_order_relaxed);
|
||||
|
||||
while (!chunk->IsSentry()) {
|
||||
// Cache next chunk in case this chunk is destroyed.
|
||||
SerialArenaChunk* next_chunk = chunk->next_chunk();
|
||||
fn(chunk);
|
||||
chunk = next_chunk;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Functor>
|
||||
void ThreadSafeArena::PerConstSerialArenaInChunk(Functor fn) const {
|
||||
WalkConstSerialArenaChunk([&fn](const SerialArenaChunk* chunk) {
|
||||
for (const auto& each : chunk->arenas()) {
|
||||
const SerialArena* serial = each.load(std::memory_order_acquire);
|
||||
// It is possible that newly added SerialArena is not updated although
|
||||
// size was. This is acceptable for SpaceAllocated and SpaceUsed.
|
||||
if (serial == nullptr) continue;
|
||||
fn(serial);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
uint64_t ThreadSafeArena::SpaceAllocated() const {
|
||||
uint64_t space_allocated = first_arena_.SpaceAllocated();
|
||||
PerConstSerialArenaInChunk([&space_allocated](const SerialArena* serial) {
|
||||
space_allocated += serial->SpaceAllocated();
|
||||
});
|
||||
return space_allocated;
|
||||
}
|
||||
|
||||
uint64_t ThreadSafeArena::SpaceUsed() const {
|
||||
// First arena is inlined to ThreadSafeArena and the first block's overhead is
|
||||
// smaller than others that contain SerialArena.
|
||||
uint64_t space_used = first_arena_.SpaceUsed();
|
||||
PerConstSerialArenaInChunk([&space_used](const SerialArena* serial) {
|
||||
// SerialArena on chunks directly allocated from the block and needs to be
|
||||
// subtracted from SpaceUsed.
|
||||
space_used += serial->SpaceUsed() - kSerialArenaSize;
|
||||
});
|
||||
return space_used - (alloc_policy_.get() ? sizeof(AllocationPolicy) : 0);
|
||||
}
|
||||
|
||||
template <AllocationClient alloc_client>
|
||||
PROTOBUF_NOINLINE void* ThreadSafeArena::AllocateAlignedFallback(size_t n) {
|
||||
return GetSerialArenaFallback(n)->AllocateAligned<alloc_client>(n);
|
||||
}
|
||||
|
||||
template void* ThreadSafeArena::AllocateAlignedFallback<
|
||||
AllocationClient::kDefault>(size_t);
|
||||
template void*
|
||||
ThreadSafeArena::AllocateAlignedFallback<AllocationClient::kArray>(size_t);
|
||||
|
||||
void ThreadSafeArena::CleanupList() {
|
||||
WalkSerialArenaChunk([](SerialArenaChunk* chunk) {
|
||||
absl::Span<std::atomic<SerialArena*>> span = chunk->arenas();
|
||||
// Walks arenas backward to handle the first serial arena the last.
|
||||
// Destroying in reverse-order to the construction is often assumed by users
|
||||
// and required not to break inter-object dependencies. (b/247560530)
|
||||
for (auto it = span.rbegin(); it != span.rend(); ++it) {
|
||||
SerialArena* serial = it->load(std::memory_order_relaxed);
|
||||
GOOGLE_DCHECK_NE(serial, nullptr);
|
||||
serial->CleanupList();
|
||||
}
|
||||
});
|
||||
// First arena must be cleaned up last. (b/247560530)
|
||||
first_arena_.CleanupList();
|
||||
}
|
||||
|
||||
PROTOBUF_NOINLINE
|
||||
SerialArena* ThreadSafeArena::GetSerialArenaFallback(size_t n) {
|
||||
void* const id = &thread_cache();
|
||||
if (id == first_owner_) {
|
||||
CacheSerialArena(&first_arena_);
|
||||
return &first_arena_;
|
||||
}
|
||||
|
||||
// Search matching SerialArena.
|
||||
SerialArena* serial = nullptr;
|
||||
WalkConstSerialArenaChunk([&serial, id](const SerialArenaChunk* chunk) {
|
||||
absl::Span<const std::atomic<void*>> ids = chunk->ids();
|
||||
for (uint32_t i = 0; i < ids.size(); ++i) {
|
||||
if (ids[i].load(std::memory_order_relaxed) == id) {
|
||||
serial = chunk->arena(i).load(std::memory_order_relaxed);
|
||||
GOOGLE_DCHECK_NE(serial, nullptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!serial) {
|
||||
// This thread doesn't have any SerialArena, which also means it doesn't
|
||||
// have any blocks yet. So we'll allocate its first block now. It must be
|
||||
// big enough to host SerialArena and the pending request.
|
||||
serial = SerialArena::New(
|
||||
AllocateMemory(alloc_policy_.get(), 0, n + kSerialArenaSize), *this);
|
||||
|
||||
AddSerialArena(id, serial);
|
||||
}
|
||||
|
||||
CacheSerialArena(serial);
|
||||
return serial;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
void* Arena::Allocate(size_t n) { return impl_.AllocateAligned(n); }
|
||||
|
||||
void* Arena::AllocateForArray(size_t n) {
|
||||
return impl_.AllocateAligned<internal::AllocationClient::kArray>(n);
|
||||
}
|
||||
|
||||
void* Arena::AllocateAlignedWithCleanup(size_t n, size_t align,
|
||||
void (*destructor)(void*)) {
|
||||
return impl_.AllocateAlignedWithCleanup(n, align, destructor);
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
773
libs/protobuf/src/google/protobuf/arena.h
Normal file
773
libs/protobuf/src/google/protobuf/arena.h
Normal file
@@ -0,0 +1,773 @@
|
||||
// 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.
|
||||
|
||||
// This file defines an Arena allocator for better allocation performance.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ARENA_H__
|
||||
#define GOOGLE_PROTOBUF_ARENA_H__
|
||||
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#if defined(_MSC_VER) && !defined(_LIBCPP_STD_VER) && !_HAS_EXCEPTIONS
|
||||
// Work around bugs in MSVC <typeinfo> header when _HAS_EXCEPTIONS=0.
|
||||
#include <exception>
|
||||
#include <typeinfo>
|
||||
namespace std {
|
||||
using type_info = ::type_info;
|
||||
}
|
||||
#else
|
||||
#include <typeinfo>
|
||||
#endif
|
||||
|
||||
#include <type_traits>
|
||||
#include "google/protobuf/arena_config.h"
|
||||
#include "google/protobuf/arena_impl.h"
|
||||
#include "google/protobuf/port.h"
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
#ifdef SWIG
|
||||
#error "You cannot SWIG proto headers"
|
||||
#endif
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
struct ArenaOptions; // defined below
|
||||
class Arena; // defined below
|
||||
class Message; // defined in message.h
|
||||
class MessageLite;
|
||||
template <typename Key, typename T>
|
||||
class Map;
|
||||
|
||||
namespace arena_metrics {
|
||||
|
||||
void EnableArenaMetrics(ArenaOptions* options);
|
||||
|
||||
} // namespace arena_metrics
|
||||
|
||||
namespace TestUtil {
|
||||
class ReflectionTester; // defined in test_util.h
|
||||
} // namespace TestUtil
|
||||
|
||||
namespace internal {
|
||||
|
||||
struct ArenaTestPeer; // defined in arena_test_util.h
|
||||
class InternalMetadata; // defined in metadata_lite.h
|
||||
class LazyField; // defined in lazy_field.h
|
||||
class EpsCopyInputStream; // defined in parse_context.h
|
||||
class RepeatedPtrFieldBase; // defined in repeated_ptr_field.h
|
||||
class TcParser; // defined in generated_message_tctable_impl.h
|
||||
|
||||
template <typename Type>
|
||||
class GenericTypeHandler; // defined in repeated_field.h
|
||||
|
||||
template <bool destructor_skippable, typename T>
|
||||
struct ObjectDestructor {
|
||||
constexpr static void (*destructor)(void*) =
|
||||
&internal::cleanup::arena_destruct_object<T>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ObjectDestructor<true, T> {
|
||||
constexpr static void (*destructor)(void*) = nullptr;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void arena_delete_object(void* object) {
|
||||
delete reinterpret_cast<T*>(object);
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
// ArenaOptions provides optional additional parameters to arena construction
|
||||
// that control its block-allocation behavior.
|
||||
struct ArenaOptions {
|
||||
// This defines the size of the first block requested from the system malloc.
|
||||
// Subsequent block sizes will increase in a geometric series up to a maximum.
|
||||
size_t start_block_size;
|
||||
|
||||
// This defines the maximum block size requested from system malloc (unless an
|
||||
// individual arena allocation request occurs with a size larger than this
|
||||
// maximum). Requested block sizes increase up to this value, then remain
|
||||
// here.
|
||||
size_t max_block_size;
|
||||
|
||||
// An initial block of memory for the arena to use, or nullptr for none. If
|
||||
// provided, the block must live at least as long as the arena itself. The
|
||||
// creator of the Arena retains ownership of the block after the Arena is
|
||||
// destroyed.
|
||||
char* initial_block;
|
||||
|
||||
// The size of the initial block, if provided.
|
||||
size_t initial_block_size;
|
||||
|
||||
// A function pointer to an alloc method that returns memory blocks of size
|
||||
// requested. By default, it contains a ptr to the malloc function.
|
||||
//
|
||||
// NOTE: block_alloc and dealloc functions are expected to behave like
|
||||
// malloc and free, including Asan poisoning.
|
||||
void* (*block_alloc)(size_t);
|
||||
// A function pointer to a dealloc method that takes ownership of the blocks
|
||||
// from the arena. By default, it contains a ptr to a wrapper function that
|
||||
// calls free.
|
||||
void (*block_dealloc)(void*, size_t);
|
||||
|
||||
ArenaOptions()
|
||||
: start_block_size(internal::AllocationPolicy::kDefaultStartBlockSize),
|
||||
max_block_size(internal::GetDefaultArenaMaxBlockSize()),
|
||||
initial_block(nullptr),
|
||||
initial_block_size(0),
|
||||
block_alloc(nullptr),
|
||||
block_dealloc(nullptr),
|
||||
make_metrics_collector(nullptr) {}
|
||||
|
||||
private:
|
||||
// If make_metrics_collector is not nullptr, it will be called at Arena init
|
||||
// time. It may return a pointer to a collector instance that will be notified
|
||||
// of interesting events related to the arena.
|
||||
internal::ArenaMetricsCollector* (*make_metrics_collector)();
|
||||
|
||||
internal::ArenaMetricsCollector* MetricsCollector() const {
|
||||
return make_metrics_collector ? (*make_metrics_collector)() : nullptr;
|
||||
}
|
||||
|
||||
internal::AllocationPolicy AllocationPolicy() const {
|
||||
internal::AllocationPolicy res;
|
||||
res.start_block_size = start_block_size;
|
||||
res.max_block_size = max_block_size;
|
||||
res.block_alloc = block_alloc;
|
||||
res.block_dealloc = block_dealloc;
|
||||
return res;
|
||||
}
|
||||
|
||||
friend void arena_metrics::EnableArenaMetrics(ArenaOptions*);
|
||||
|
||||
friend class Arena;
|
||||
friend class ArenaOptionsTestFriend;
|
||||
};
|
||||
|
||||
// Arena allocator. Arena allocation replaces ordinary (heap-based) allocation
|
||||
// with new/delete, and improves performance by aggregating allocations into
|
||||
// larger blocks and freeing allocations all at once. Protocol messages are
|
||||
// allocated on an arena by using Arena::CreateMessage<T>(Arena*), below, and
|
||||
// are automatically freed when the arena is destroyed.
|
||||
//
|
||||
// This is a thread-safe implementation: multiple threads may allocate from the
|
||||
// arena concurrently. Destruction is not thread-safe and the destructing
|
||||
// thread must synchronize with users of the arena first.
|
||||
//
|
||||
// An arena provides two allocation interfaces: CreateMessage<T>, which works
|
||||
// for arena-enabled proto2 message types as well as other types that satisfy
|
||||
// the appropriate protocol (described below), and Create<T>, which works for
|
||||
// any arbitrary type T. CreateMessage<T> is better when the type T supports it,
|
||||
// because this interface (i) passes the arena pointer to the created object so
|
||||
// that its sub-objects and internal allocations can use the arena too, and (ii)
|
||||
// elides the object's destructor call when possible. Create<T> does not place
|
||||
// any special requirements on the type T, and will invoke the object's
|
||||
// destructor when the arena is destroyed.
|
||||
//
|
||||
// The arena message allocation protocol, required by
|
||||
// CreateMessage<T>(Arena* arena, Args&&... args), is as follows:
|
||||
//
|
||||
// - The type T must have (at least) two constructors: a constructor callable
|
||||
// with `args` (without `arena`), called when a T is allocated on the heap;
|
||||
// and a constructor callable with `Arena* arena, Args&&... args`, called when
|
||||
// a T is allocated on an arena. If the second constructor is called with a
|
||||
// null arena pointer, it must be equivalent to invoking the first
|
||||
// (`args`-only) constructor.
|
||||
//
|
||||
// - The type T must have a particular type trait: a nested type
|
||||
// |InternalArenaConstructable_|. This is usually a typedef to |void|. If no
|
||||
// such type trait exists, then the instantiation CreateMessage<T> will fail
|
||||
// to compile.
|
||||
//
|
||||
// - The type T *may* have the type trait |DestructorSkippable_|. If this type
|
||||
// trait is present in the type, then its destructor will not be called if and
|
||||
// only if it was passed a non-null arena pointer. If this type trait is not
|
||||
// present on the type, then its destructor is always called when the
|
||||
// containing arena is destroyed.
|
||||
//
|
||||
// This protocol is implemented by all arena-enabled proto2 message classes as
|
||||
// well as protobuf container types like RepeatedPtrField and Map. The protocol
|
||||
// is internal to protobuf and is not guaranteed to be stable. Non-proto types
|
||||
// should not rely on this protocol.
|
||||
class PROTOBUF_EXPORT PROTOBUF_ALIGNAS(8) Arena final {
|
||||
public:
|
||||
// Default constructor with sensible default options, tuned for average
|
||||
// use-cases.
|
||||
inline Arena() : impl_() {}
|
||||
|
||||
// Construct an arena with default options, except for the supplied
|
||||
// initial block. It is more efficient to use this constructor
|
||||
// instead of passing ArenaOptions if the only configuration needed
|
||||
// by the caller is supplying an initial block.
|
||||
inline Arena(char* initial_block, size_t initial_block_size)
|
||||
: impl_(initial_block, initial_block_size) {}
|
||||
|
||||
// Arena constructor taking custom options. See ArenaOptions above for
|
||||
// descriptions of the options available.
|
||||
explicit Arena(const ArenaOptions& options)
|
||||
: impl_(options.initial_block, options.initial_block_size,
|
||||
options.AllocationPolicy()) {}
|
||||
|
||||
// Block overhead. Use this as a guide for how much to over-allocate the
|
||||
// initial block if you want an allocation of size N to fit inside it.
|
||||
//
|
||||
// WARNING: if you allocate multiple objects, it is difficult to guarantee
|
||||
// that a series of allocations will fit in the initial block, especially if
|
||||
// Arena changes its alignment guarantees in the future!
|
||||
static const size_t kBlockOverhead =
|
||||
internal::ThreadSafeArena::kBlockHeaderSize +
|
||||
internal::ThreadSafeArena::kSerialArenaSize;
|
||||
|
||||
inline ~Arena() {}
|
||||
|
||||
// API to create proto2 message objects on the arena. If the arena passed in
|
||||
// is nullptr, then a heap allocated object is returned. Type T must be a
|
||||
// message defined in a .proto file with cc_enable_arenas set to true,
|
||||
// otherwise a compilation error will occur.
|
||||
//
|
||||
// RepeatedField and RepeatedPtrField may also be instantiated directly on an
|
||||
// arena with this method.
|
||||
//
|
||||
// This function also accepts any type T that satisfies the arena message
|
||||
// allocation protocol, documented above.
|
||||
template <typename T, typename... Args>
|
||||
PROTOBUF_ALWAYS_INLINE static T* CreateMessage(Arena* arena, Args&&... args) {
|
||||
static_assert(
|
||||
InternalHelper<T>::is_arena_constructable::value,
|
||||
"CreateMessage can only construct types that are ArenaConstructable");
|
||||
// We must delegate to CreateMaybeMessage() and NOT CreateMessageInternal()
|
||||
// because protobuf generated classes specialize CreateMaybeMessage() and we
|
||||
// need to use that specialization for code size reasons.
|
||||
return Arena::CreateMaybeMessage<T>(arena, static_cast<Args&&>(args)...);
|
||||
}
|
||||
|
||||
// API to create any objects on the arena. Note that only the object will
|
||||
// be created on the arena; the underlying ptrs (in case of a proto2 message)
|
||||
// will be still heap allocated. Proto messages should usually be allocated
|
||||
// with CreateMessage<T>() instead.
|
||||
//
|
||||
// Note that even if T satisfies the arena message construction protocol
|
||||
// (InternalArenaConstructable_ trait and optional DestructorSkippable_
|
||||
// trait), as described above, this function does not follow the protocol;
|
||||
// instead, it treats T as a black-box type, just as if it did not have these
|
||||
// traits. Specifically, T's constructor arguments will always be only those
|
||||
// passed to Create<T>() -- no additional arena pointer is implicitly added.
|
||||
// Furthermore, the destructor will always be called at arena destruction time
|
||||
// (unless the destructor is trivial). Hence, from T's point of view, it is as
|
||||
// if the object were allocated on the heap (except that the underlying memory
|
||||
// is obtained from the arena).
|
||||
template <typename T, typename... Args>
|
||||
PROTOBUF_NDEBUG_INLINE static T* Create(Arena* arena, Args&&... args) {
|
||||
return CreateInternal<T>(arena, std::is_convertible<T*, MessageLite*>(),
|
||||
static_cast<Args&&>(args)...);
|
||||
}
|
||||
|
||||
// API to delete any objects not on an arena. This can be used to safely
|
||||
// clean up messages or repeated fields without knowing whether or not they're
|
||||
// owned by an arena. The pointer passed to this function should not be used
|
||||
// again.
|
||||
template <typename T>
|
||||
PROTOBUF_ALWAYS_INLINE static void Destroy(T* obj) {
|
||||
if (InternalGetOwningArena(obj) == nullptr) delete obj;
|
||||
}
|
||||
|
||||
// Allocates memory with the specific size and alignment.
|
||||
void* AllocateAligned(size_t size, size_t align = 8) {
|
||||
if (align <= 8) {
|
||||
return Allocate(internal::AlignUpTo8(size));
|
||||
} else {
|
||||
// We are wasting space by over allocating align - 8 bytes. Compared
|
||||
// to a dedicated function that takes current alignment in consideration.
|
||||
// Such a scheme would only waste (align - 8)/2 bytes on average, but
|
||||
// requires a dedicated function in the outline arena allocation
|
||||
// functions. Possibly re-evaluate tradeoffs later.
|
||||
return internal::AlignTo(Allocate(size + align - 8), align);
|
||||
}
|
||||
}
|
||||
|
||||
// Create an array of object type T on the arena *without* invoking the
|
||||
// constructor of T. If `arena` is null, then the return value should be freed
|
||||
// with `delete[] x;` (or `::operator delete[](x);`).
|
||||
// To ensure safe uses, this function checks at compile time
|
||||
// (when compiled as C++11) that T is trivially default-constructible and
|
||||
// trivially destructible.
|
||||
template <typename T>
|
||||
PROTOBUF_NDEBUG_INLINE static T* CreateArray(Arena* arena,
|
||||
size_t num_elements) {
|
||||
static_assert(std::is_trivial<T>::value,
|
||||
"CreateArray requires a trivially constructible type");
|
||||
static_assert(std::is_trivially_destructible<T>::value,
|
||||
"CreateArray requires a trivially destructible type");
|
||||
GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() / sizeof(T))
|
||||
<< "Requested size is too large to fit into size_t.";
|
||||
if (arena == nullptr) {
|
||||
return static_cast<T*>(::operator new[](num_elements * sizeof(T)));
|
||||
} else {
|
||||
return arena->CreateInternalRawArray<T>(num_elements);
|
||||
}
|
||||
}
|
||||
|
||||
// The following are routines are for monitoring. They will approximate the
|
||||
// total sum allocated and used memory, but the exact value is an
|
||||
// implementation deal. For instance allocated space depends on growth
|
||||
// policies. Do not use these in unit tests.
|
||||
// Returns the total space allocated by the arena, which is the sum of the
|
||||
// sizes of the underlying blocks.
|
||||
uint64_t SpaceAllocated() const { return impl_.SpaceAllocated(); }
|
||||
// Returns the total space used by the arena. Similar to SpaceAllocated but
|
||||
// does not include free space and block overhead. This is a best-effort
|
||||
// estimate and may inaccurately calculate space used by other threads
|
||||
// executing concurrently with the call to this method. These inaccuracies
|
||||
// are due to race conditions, and are bounded but unpredictable. Stale data
|
||||
// can lead to underestimates of the space used, and race conditions can lead
|
||||
// to overestimates (up to the current block size).
|
||||
uint64_t SpaceUsed() const { return impl_.SpaceUsed(); }
|
||||
|
||||
// Frees all storage allocated by this arena after calling destructors
|
||||
// registered with OwnDestructor() and freeing objects registered with Own().
|
||||
// Any objects allocated on this arena are unusable after this call. It also
|
||||
// returns the total space used by the arena which is the sums of the sizes
|
||||
// of the allocated blocks. This method is not thread-safe.
|
||||
uint64_t Reset() { return impl_.Reset(); }
|
||||
|
||||
// Adds |object| to a list of heap-allocated objects to be freed with |delete|
|
||||
// when the arena is destroyed or reset.
|
||||
template <typename T>
|
||||
PROTOBUF_ALWAYS_INLINE void Own(T* object) {
|
||||
OwnInternal(object, std::is_convertible<T*, MessageLite*>());
|
||||
}
|
||||
|
||||
// Adds |object| to a list of objects whose destructors will be manually
|
||||
// called when the arena is destroyed or reset. This differs from Own() in
|
||||
// that it does not free the underlying memory with |delete|; hence, it is
|
||||
// normally only used for objects that are placement-newed into
|
||||
// arena-allocated memory.
|
||||
template <typename T>
|
||||
PROTOBUF_ALWAYS_INLINE void OwnDestructor(T* object) {
|
||||
if (object != nullptr) {
|
||||
impl_.AddCleanup(object, &internal::cleanup::arena_destruct_object<T>);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds a custom member function on an object to the list of destructors that
|
||||
// will be manually called when the arena is destroyed or reset. This differs
|
||||
// from OwnDestructor() in that any member function may be specified, not only
|
||||
// the class destructor.
|
||||
PROTOBUF_ALWAYS_INLINE void OwnCustomDestructor(void* object,
|
||||
void (*destruct)(void*)) {
|
||||
impl_.AddCleanup(object, destruct);
|
||||
}
|
||||
|
||||
// Retrieves the arena associated with |value| if |value| is an arena-capable
|
||||
// message, or nullptr otherwise. If possible, the call resolves at compile
|
||||
// time. Note that we can often devirtualize calls to `value->GetArena()` so
|
||||
// usually calling this method is unnecessary.
|
||||
template <typename T>
|
||||
PROTOBUF_ALWAYS_INLINE static Arena* GetArena(const T* value) {
|
||||
return GetArenaInternal(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class InternalHelper {
|
||||
private:
|
||||
// A SFINAE friendly trait that probes for `U` but always evalues to
|
||||
// `Arena*`.
|
||||
template <typename U>
|
||||
using EnableIfArena =
|
||||
typename std::enable_if<std::is_same<Arena*, U>::value, Arena*>::type;
|
||||
|
||||
// Rather than use SFINAE that must fully cover the space of options in a
|
||||
// mutually exclusive fashion, we use implicit conversions to base classes
|
||||
// to force an explicit ranking for our preferences. The lowest ranked
|
||||
// version that compiles will be accepted.
|
||||
struct Rank2 {};
|
||||
struct Rank1 : Rank2 {};
|
||||
struct Rank0 : Rank1 {};
|
||||
|
||||
static Arena* GetOwningArena(const T* p) {
|
||||
return GetOwningArena(Rank0{}, p);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
static auto GetOwningArena(Rank0, const U* p)
|
||||
-> EnableIfArena<decltype(p->GetOwningArena())> {
|
||||
return p->GetOwningArena();
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
static Arena* GetOwningArena(Rank1, const U* p) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void InternalSwap(T* a, T* b) { a->InternalSwap(b); }
|
||||
|
||||
static Arena* GetArenaForAllocation(const T* p) {
|
||||
return GetArenaForAllocation(Rank0{}, p);
|
||||
}
|
||||
|
||||
static Arena* GetArena(const T* p) {
|
||||
// Rather than replicate probing for `GetArena` with fallback to nullptr,
|
||||
// we borrow the implementation of `GetArenaForAllocation` but skip
|
||||
// `Rank0` which probes for `GetArenaForAllocation`.
|
||||
return GetArenaForAllocation(Rank1{}, p);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
static auto GetArenaForAllocation(Rank0, const U* p)
|
||||
-> EnableIfArena<decltype(p->GetArenaForAllocation())> {
|
||||
return p->GetArenaForAllocation();
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
static auto GetArenaForAllocation(Rank1, const U* p)
|
||||
-> EnableIfArena<decltype(p->GetArena())> {
|
||||
return p->GetArena();
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
static Arena* GetArenaForAllocation(Rank2, const U* p) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
static char DestructorSkippable(const typename U::DestructorSkippable_*);
|
||||
template <typename U>
|
||||
static double DestructorSkippable(...);
|
||||
|
||||
typedef std::integral_constant<
|
||||
bool, sizeof(DestructorSkippable<T>(static_cast<const T*>(0))) ==
|
||||
sizeof(char) ||
|
||||
std::is_trivially_destructible<T>::value>
|
||||
is_destructor_skippable;
|
||||
|
||||
template <typename U>
|
||||
static char ArenaConstructable(
|
||||
const typename U::InternalArenaConstructable_*);
|
||||
template <typename U>
|
||||
static double ArenaConstructable(...);
|
||||
|
||||
typedef std::integral_constant<bool, sizeof(ArenaConstructable<T>(
|
||||
static_cast<const T*>(0))) ==
|
||||
sizeof(char)>
|
||||
is_arena_constructable;
|
||||
|
||||
|
||||
template <typename... Args>
|
||||
static T* Construct(void* ptr, Args&&... args) {
|
||||
return new (ptr) T(static_cast<Args&&>(args)...);
|
||||
}
|
||||
|
||||
static inline PROTOBUF_ALWAYS_INLINE T* New() {
|
||||
return new T(nullptr);
|
||||
}
|
||||
|
||||
friend class Arena;
|
||||
friend class TestUtil::ReflectionTester;
|
||||
};
|
||||
|
||||
// Provides access to protected GetOwningArena to generated messages. For
|
||||
// internal use only.
|
||||
template <typename T>
|
||||
static Arena* InternalGetOwningArena(const T* p) {
|
||||
return InternalHelper<T>::GetOwningArena(p);
|
||||
}
|
||||
|
||||
// Provides access to protected GetArenaForAllocation to generated messages.
|
||||
// For internal use only.
|
||||
template <typename T>
|
||||
static Arena* InternalGetArenaForAllocation(const T* p) {
|
||||
return InternalHelper<T>::GetArenaForAllocation(p);
|
||||
}
|
||||
|
||||
// Creates message-owned arena. For internal use only.
|
||||
static Arena* InternalCreateMessageOwnedArena() {
|
||||
return new Arena(internal::MessageOwned{});
|
||||
}
|
||||
|
||||
// Checks whether this arena is message-owned. For internal use only.
|
||||
bool InternalIsMessageOwnedArena() { return IsMessageOwned(); }
|
||||
|
||||
// Helper typetraits that indicates support for arenas in a type T at compile
|
||||
// time. This is public only to allow construction of higher-level templated
|
||||
// utilities.
|
||||
//
|
||||
// is_arena_constructable<T>::value is true if the message type T has arena
|
||||
// support enabled, and false otherwise.
|
||||
//
|
||||
// is_destructor_skippable<T>::value is true if the message type T has told
|
||||
// the arena that it is safe to skip the destructor, and false otherwise.
|
||||
//
|
||||
// This is inside Arena because only Arena has the friend relationships
|
||||
// necessary to see the underlying generated code traits.
|
||||
template <typename T>
|
||||
struct is_arena_constructable : InternalHelper<T>::is_arena_constructable {};
|
||||
template <typename T>
|
||||
struct is_destructor_skippable : InternalHelper<T>::is_destructor_skippable {
|
||||
};
|
||||
|
||||
private:
|
||||
internal::ThreadSafeArena impl_;
|
||||
|
||||
// Constructor solely used by message-owned arena.
|
||||
inline Arena(internal::MessageOwned) : impl_(internal::MessageOwned{}) {}
|
||||
|
||||
// Checks whether this arena is message-owned.
|
||||
PROTOBUF_ALWAYS_INLINE bool IsMessageOwned() const {
|
||||
return impl_.IsMessageOwned();
|
||||
}
|
||||
|
||||
void ReturnArrayMemory(void* p, size_t size) {
|
||||
impl_.ReturnArrayMemory(p, size);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
PROTOBUF_NDEBUG_INLINE static T* CreateMessageInternal(Arena* arena,
|
||||
Args&&... args) {
|
||||
static_assert(
|
||||
InternalHelper<T>::is_arena_constructable::value,
|
||||
"CreateMessage can only construct types that are ArenaConstructable");
|
||||
if (arena == nullptr) {
|
||||
return new T(nullptr, static_cast<Args&&>(args)...);
|
||||
} else {
|
||||
return arena->DoCreateMessage<T>(static_cast<Args&&>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
// This specialization for no arguments is necessary, because its behavior is
|
||||
// slightly different. When the arena pointer is nullptr, it calls T()
|
||||
// instead of T(nullptr).
|
||||
template <typename T>
|
||||
PROTOBUF_NDEBUG_INLINE static T* CreateMessageInternal(Arena* arena) {
|
||||
static_assert(
|
||||
InternalHelper<T>::is_arena_constructable::value,
|
||||
"CreateMessage can only construct types that are ArenaConstructable");
|
||||
if (arena == nullptr) {
|
||||
// Generated arena constructor T(Arena*) is protected. Call via
|
||||
// InternalHelper.
|
||||
return InternalHelper<T>::New();
|
||||
} else {
|
||||
return arena->DoCreateMessage<T>();
|
||||
}
|
||||
}
|
||||
|
||||
PROTOBUF_NDEBUG_INLINE void* AllocateInternal(size_t size, size_t align,
|
||||
void (*destructor)(void*)) {
|
||||
// Monitor allocation if needed.
|
||||
if (destructor == nullptr) {
|
||||
return AllocateAligned(size, align);
|
||||
} else {
|
||||
return AllocateAlignedWithCleanup(size, align, destructor);
|
||||
}
|
||||
}
|
||||
|
||||
// CreateMessage<T> requires that T supports arenas, but this private method
|
||||
// works whether or not T supports arenas. These are not exposed to user code
|
||||
// as it can cause confusing API usages, and end up having double free in
|
||||
// user code. These are used only internally from LazyField and Repeated
|
||||
// fields, since they are designed to work in all mode combinations.
|
||||
template <typename Msg, typename... Args>
|
||||
PROTOBUF_ALWAYS_INLINE static Msg* DoCreateMaybeMessage(Arena* arena,
|
||||
std::true_type,
|
||||
Args&&... args) {
|
||||
return CreateMessageInternal<Msg>(arena, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
PROTOBUF_ALWAYS_INLINE static T* DoCreateMaybeMessage(Arena* arena,
|
||||
std::false_type,
|
||||
Args&&... args) {
|
||||
return Create<T>(arena, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
PROTOBUF_ALWAYS_INLINE static T* CreateMaybeMessage(Arena* arena,
|
||||
Args&&... args) {
|
||||
return DoCreateMaybeMessage<T>(arena, is_arena_constructable<T>(),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Just allocate the required size for the given type assuming the
|
||||
// type has a trivial constructor.
|
||||
template <typename T>
|
||||
PROTOBUF_NDEBUG_INLINE T* CreateInternalRawArray(size_t num_elements) {
|
||||
GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() / sizeof(T))
|
||||
<< "Requested size is too large to fit into size_t.";
|
||||
// We count on compiler to realize that if sizeof(T) is a multiple of
|
||||
// 8 AlignUpTo can be elided.
|
||||
const size_t n = sizeof(T) * num_elements;
|
||||
return static_cast<T*>(AllocateAlignedForArray(n, alignof(T)));
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
PROTOBUF_NDEBUG_INLINE T* DoCreateMessage(Args&&... args) {
|
||||
return InternalHelper<T>::Construct(
|
||||
AllocateInternal(sizeof(T), alignof(T),
|
||||
internal::ObjectDestructor<
|
||||
InternalHelper<T>::is_destructor_skippable::value,
|
||||
T>::destructor),
|
||||
this, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// CreateInArenaStorage is used to implement map field. Without it,
|
||||
// Map need to call generated message's protected arena constructor,
|
||||
// which needs to declare Map as friend of generated message.
|
||||
template <typename T, typename... Args>
|
||||
static void CreateInArenaStorage(T* ptr, Arena* arena, Args&&... args) {
|
||||
CreateInArenaStorageInternal(ptr, arena,
|
||||
typename is_arena_constructable<T>::type(),
|
||||
std::forward<Args>(args)...);
|
||||
if (arena != nullptr) {
|
||||
RegisterDestructorInternal(
|
||||
ptr, arena,
|
||||
typename InternalHelper<T>::is_destructor_skippable::type());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static void CreateInArenaStorageInternal(T* ptr, Arena* arena,
|
||||
std::true_type, Args&&... args) {
|
||||
InternalHelper<T>::Construct(ptr, arena, std::forward<Args>(args)...);
|
||||
}
|
||||
template <typename T, typename... Args>
|
||||
static void CreateInArenaStorageInternal(T* ptr, Arena* /* arena */,
|
||||
std::false_type, Args&&... args) {
|
||||
new (ptr) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void RegisterDestructorInternal(T* /* ptr */, Arena* /* arena */,
|
||||
std::true_type) {}
|
||||
template <typename T>
|
||||
static void RegisterDestructorInternal(T* ptr, Arena* arena,
|
||||
std::false_type) {
|
||||
arena->OwnDestructor(ptr);
|
||||
}
|
||||
|
||||
// These implement Create(). The second parameter has type 'true_type' if T is
|
||||
// a subtype of Message and 'false_type' otherwise.
|
||||
template <typename T, typename... Args>
|
||||
PROTOBUF_ALWAYS_INLINE static T* CreateInternal(Arena* arena, std::true_type,
|
||||
Args&&... args) {
|
||||
if (arena == nullptr) {
|
||||
return new T(std::forward<Args>(args)...);
|
||||
} else {
|
||||
auto destructor =
|
||||
internal::ObjectDestructor<std::is_trivially_destructible<T>::value,
|
||||
T>::destructor;
|
||||
T* result =
|
||||
new (arena->AllocateInternal(sizeof(T), alignof(T), destructor))
|
||||
T(std::forward<Args>(args)...);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
template <typename T, typename... Args>
|
||||
PROTOBUF_ALWAYS_INLINE static T* CreateInternal(Arena* arena, std::false_type,
|
||||
Args&&... args) {
|
||||
if (arena == nullptr) {
|
||||
return new T(std::forward<Args>(args)...);
|
||||
} else {
|
||||
auto destructor =
|
||||
internal::ObjectDestructor<std::is_trivially_destructible<T>::value,
|
||||
T>::destructor;
|
||||
return new (arena->AllocateInternal(sizeof(T), alignof(T), destructor))
|
||||
T(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
// These implement Own(), which registers an object for deletion (destructor
|
||||
// call and operator delete()). The second parameter has type 'true_type' if T
|
||||
// is a subtype of Message and 'false_type' otherwise. Collapsing
|
||||
// all template instantiations to one for generic Message reduces code size,
|
||||
// using the virtual destructor instead.
|
||||
template <typename T>
|
||||
PROTOBUF_ALWAYS_INLINE void OwnInternal(T* object, std::true_type) {
|
||||
if (object != nullptr) {
|
||||
impl_.AddCleanup(object, &internal::arena_delete_object<MessageLite>);
|
||||
}
|
||||
}
|
||||
template <typename T>
|
||||
PROTOBUF_ALWAYS_INLINE void OwnInternal(T* object, std::false_type) {
|
||||
if (object != nullptr) {
|
||||
impl_.AddCleanup(object, &internal::arena_delete_object<T>);
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation for GetArena(). Only message objects with
|
||||
// InternalArenaConstructable_ tags can be associated with an arena, and such
|
||||
// objects must implement a GetArena() method.
|
||||
template <typename T>
|
||||
PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* value) {
|
||||
return InternalHelper<T>::GetArena(value);
|
||||
}
|
||||
|
||||
void* AllocateAlignedForArray(size_t n, size_t align) {
|
||||
if (align <= 8) {
|
||||
return AllocateForArray(internal::AlignUpTo8(n));
|
||||
} else {
|
||||
// We are wasting space by over allocating align - 8 bytes. Compared
|
||||
// to a dedicated function that takes current alignment in consideration.
|
||||
// Such a scheme would only waste (align - 8)/2 bytes on average, but
|
||||
// requires a dedicated function in the outline arena allocation
|
||||
// functions. Possibly re-evaluate tradeoffs later.
|
||||
return internal::AlignTo(AllocateForArray(n + align - 8), align);
|
||||
}
|
||||
}
|
||||
|
||||
void* Allocate(size_t n);
|
||||
void* AllocateForArray(size_t n);
|
||||
void* AllocateAlignedWithCleanup(size_t n, size_t align,
|
||||
void (*destructor)(void*));
|
||||
|
||||
template <typename Type>
|
||||
friend class internal::GenericTypeHandler;
|
||||
friend class internal::InternalMetadata; // For user_arena().
|
||||
friend class internal::LazyField; // For CreateMaybeMessage.
|
||||
friend class internal::EpsCopyInputStream; // For parser performance
|
||||
friend class internal::TcParser; // For parser performance
|
||||
friend class MessageLite;
|
||||
template <typename Key, typename T>
|
||||
friend class Map;
|
||||
template <typename>
|
||||
friend class RepeatedField; // For ReturnArrayMemory
|
||||
friend class internal::RepeatedPtrFieldBase; // For ReturnArrayMemory
|
||||
friend struct internal::ArenaTestPeer;
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ARENA_H__
|
||||
45
libs/protobuf/src/google/protobuf/arena_align.cc
Normal file
45
libs/protobuf/src/google/protobuf/arena_align.cc
Normal file
@@ -0,0 +1,45 @@
|
||||
// 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/arena_align.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// There are still compilers (open source) requiring a definition for constexpr.
|
||||
constexpr size_t ArenaAlignDefault::align; // NOLINT
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
155
libs/protobuf/src/google/protobuf/arena_align.h
Normal file
155
libs/protobuf/src/google/protobuf/arena_align.h
Normal file
@@ -0,0 +1,155 @@
|
||||
// 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.
|
||||
|
||||
// This file provides alignment utilities for use in arenas.
|
||||
//
|
||||
// `ArenaAlign` contains a single `align` data member and provides
|
||||
// the below functions which operate on the given alignment.
|
||||
//
|
||||
// Ceil(size_t n) - rounds `n` up to the nearest `align` boundary.
|
||||
// Floor(size_t n) - rounds `n` down to the nearest `align` boundary.
|
||||
// Ceil(T* P) - rounds `p` up to the nearest `align` boundary.
|
||||
// IsAligned(size_t n) - returns true if `n` is aligned to `align`
|
||||
// IsAligned(T* p) - returns true if `p` is aligned to `align`
|
||||
// CheckAligned(T* p) - returns `p`. Checks alignment of `p` in debug.
|
||||
//
|
||||
// Additionally there is an optimized `CeilDefaultAligned(T*)` method which is
|
||||
// equivalent to `Ceil(ArenaAlignDefault().CheckAlign(p))` but more efficiently
|
||||
// implemented as a 'check only' for ArenaAlignDefault.
|
||||
//
|
||||
// These classes allow for generic arena logic using 'alignment policies'.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// template <Align>
|
||||
// void* NaiveAlloc(size_t n, Align align) {
|
||||
// align.CheckAligned(n);
|
||||
// uint8_t* ptr = align.CeilDefaultAligned(ptr_);
|
||||
// ptr_ += n;
|
||||
// return ptr;
|
||||
// }
|
||||
//
|
||||
// void CallSites() {
|
||||
// void *p1 = NaiveAlloc(n, ArenaAlignDefault());
|
||||
// void *p2 = NaiveAlloc(n, ArenaAlignAs(32));
|
||||
// }
|
||||
//
|
||||
#ifndef GOOGLE_PROTOBUF_ARENA_ALIGN_H__
|
||||
#define GOOGLE_PROTOBUF_ARENA_ALIGN_H__
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "google/protobuf/stubs/logging.h"
|
||||
#include "google/protobuf/stubs/common.h"
|
||||
#include "absl/numeric/bits.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
struct ArenaAlignDefault {
|
||||
static constexpr size_t align = 8; // NOLINT
|
||||
|
||||
static constexpr bool IsAligned(size_t n) { return (n & (align - 1)) == 0; }
|
||||
|
||||
template <typename T>
|
||||
static bool IsAligned(T* ptr) {
|
||||
return (reinterpret_cast<uintptr_t>(ptr) & (align - 1)) == 0;
|
||||
}
|
||||
|
||||
static constexpr size_t Ceil(size_t n) { return (n + align - 1) & -align; }
|
||||
static constexpr size_t Floor(size_t n) { return (n & ~(align - 1)); }
|
||||
|
||||
template <typename T>
|
||||
T* Ceil(T* ptr) const {
|
||||
uintptr_t intptr = reinterpret_cast<uintptr_t>(ptr);
|
||||
return reinterpret_cast<T*>((intptr + align - 1) & -align);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* CeilDefaultAligned(T* ptr) const {
|
||||
return ArenaAlignDefault().CheckAligned(ptr);
|
||||
}
|
||||
|
||||
// Address sanitizer enabled alignment check
|
||||
template <typename T>
|
||||
static T* CheckAligned(T* ptr) {
|
||||
GOOGLE_DCHECK(IsAligned(ptr)) << static_cast<void*>(ptr);
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
struct ArenaAlign {
|
||||
static constexpr bool IsDefault() { return false; };
|
||||
|
||||
size_t align;
|
||||
|
||||
constexpr bool IsAligned(size_t n) const { return (n & (align - 1)) == 0; }
|
||||
|
||||
template <typename T>
|
||||
bool IsAligned(T* ptr) const {
|
||||
return (reinterpret_cast<uintptr_t>(ptr) & (align - 1)) == 0;
|
||||
}
|
||||
|
||||
constexpr size_t Ceil(size_t n) const { return (n + align - 1) & -align; }
|
||||
constexpr size_t Floor(size_t n) const { return (n & ~(align - 1)); }
|
||||
|
||||
template <typename T>
|
||||
T* Ceil(T* ptr) const {
|
||||
uintptr_t intptr = reinterpret_cast<uintptr_t>(ptr);
|
||||
return reinterpret_cast<T*>((intptr + align - 1) & -align);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* CeilDefaultAligned(T* ptr) const {
|
||||
return Ceil(ArenaAlignDefault().CheckAligned(ptr));
|
||||
}
|
||||
|
||||
// Address sanitizer enabled alignment check
|
||||
template <typename T>
|
||||
T* CheckAligned(T* ptr) const {
|
||||
GOOGLE_DCHECK(IsAligned(ptr)) << static_cast<void*>(ptr);
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
inline ArenaAlign ArenaAlignAs(size_t align) {
|
||||
// align must be a non zero power of 2 >= 8
|
||||
GOOGLE_DCHECK_NE(align, 0);
|
||||
GOOGLE_DCHECK(absl::has_single_bit(align)) << "Invalid alignment " << align;
|
||||
return ArenaAlign{align};
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ARENA_ALIGN_H__
|
||||
215
libs/protobuf/src/google/protobuf/arena_align_test.cc
Normal file
215
libs/protobuf/src/google/protobuf/arena_align_test.cc
Normal file
@@ -0,0 +1,215 @@
|
||||
// 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/arena_align.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
||||
using ::testing::Eq;
|
||||
|
||||
TEST(ArenaAlignDefault, Align) {
|
||||
auto align_default = ArenaAlignDefault();
|
||||
EXPECT_THAT(align_default.align, Eq(8));
|
||||
}
|
||||
|
||||
TEST(ArenaAlignDefault, Floor) {
|
||||
auto align_default = ArenaAlignDefault();
|
||||
EXPECT_THAT(align_default.Floor(0), Eq(0));
|
||||
EXPECT_THAT(align_default.Floor(1), Eq(0));
|
||||
EXPECT_THAT(align_default.Floor(7), Eq(0));
|
||||
EXPECT_THAT(align_default.Floor(8), Eq(8));
|
||||
EXPECT_THAT(align_default.Floor(9), Eq(8));
|
||||
EXPECT_THAT(align_default.Floor(15), Eq(8));
|
||||
EXPECT_THAT(align_default.Floor(16), Eq(16));
|
||||
}
|
||||
|
||||
TEST(ArenaAlignDefault, Ceil) {
|
||||
auto align_default = ArenaAlignDefault();
|
||||
EXPECT_THAT(align_default.Ceil(0), Eq(0));
|
||||
EXPECT_THAT(align_default.Ceil(1), Eq(8));
|
||||
EXPECT_THAT(align_default.Ceil(7), Eq(8));
|
||||
EXPECT_THAT(align_default.Ceil(8), Eq(8));
|
||||
EXPECT_THAT(align_default.Ceil(9), Eq(16));
|
||||
EXPECT_THAT(align_default.Ceil(15), Eq(16));
|
||||
EXPECT_THAT(align_default.Ceil(16), Eq(16));
|
||||
}
|
||||
|
||||
TEST(ArenaAlignDefault, CeilPtr) {
|
||||
alignas(8) char p[17] = {0};
|
||||
auto align_default = ArenaAlignDefault();
|
||||
EXPECT_THAT(align_default.Ceil(p + 0), Eq(p + 0));
|
||||
EXPECT_THAT(align_default.Ceil(p + 1), Eq(p + 8));
|
||||
EXPECT_THAT(align_default.Ceil(p + 7), Eq(p + 8));
|
||||
EXPECT_THAT(align_default.Ceil(p + 8), Eq(p + 8));
|
||||
EXPECT_THAT(align_default.Ceil(p + 9), Eq(p + 16));
|
||||
EXPECT_THAT(align_default.Ceil(p + 15), Eq(p + 16));
|
||||
EXPECT_THAT(align_default.Ceil(p + 16), Eq(p + 16));
|
||||
}
|
||||
|
||||
TEST(ArenaAlignDefault, CheckAligned) {
|
||||
alignas(8) char p[17] = {0};
|
||||
auto align_default = ArenaAlignDefault();
|
||||
EXPECT_THAT(align_default.CheckAligned(p + 0), Eq(p + 0));
|
||||
EXPECT_THAT(align_default.CheckAligned(p + 8), Eq(p + 8));
|
||||
EXPECT_THAT(align_default.CheckAligned(p + 16), Eq(p + 16));
|
||||
#ifdef PROTOBUF_HAS_DEATH_TEST
|
||||
EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 1), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 7), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 9), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 15), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 17), ".*");
|
||||
#endif // PROTOBUF_HAS_DEATH_TEST
|
||||
}
|
||||
|
||||
TEST(ArenaAlignDefault, CeilDefaultAligned) {
|
||||
alignas(8) char p[17] = {0};
|
||||
auto align_default = ArenaAlignDefault();
|
||||
EXPECT_THAT(align_default.CeilDefaultAligned(p + 0), Eq(p + 0));
|
||||
EXPECT_THAT(align_default.CeilDefaultAligned(p + 8), Eq(p + 8));
|
||||
EXPECT_THAT(align_default.CeilDefaultAligned(p + 16), Eq(p + 16));
|
||||
#ifdef PROTOBUF_HAS_DEATH_TEST
|
||||
EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 1), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 7), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 9), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 15), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 17), ".*");
|
||||
#endif // PROTOBUF_HAS_DEATH_TEST
|
||||
}
|
||||
|
||||
TEST(ArenaAlignDefault, IsAligned) {
|
||||
auto align_default = ArenaAlignDefault();
|
||||
EXPECT_TRUE(align_default.IsAligned(0));
|
||||
EXPECT_FALSE(align_default.IsAligned(1));
|
||||
EXPECT_FALSE(align_default.IsAligned(7));
|
||||
EXPECT_TRUE(align_default.IsAligned(8));
|
||||
EXPECT_FALSE(align_default.IsAligned(9));
|
||||
EXPECT_FALSE(align_default.IsAligned(15));
|
||||
EXPECT_TRUE(align_default.IsAligned(16));
|
||||
}
|
||||
|
||||
TEST(ArenaAlign, Align) {
|
||||
auto align_64 = ArenaAlignAs(64);
|
||||
EXPECT_THAT(align_64.align, Eq(64));
|
||||
}
|
||||
|
||||
TEST(ArenaAlign, Floor) {
|
||||
auto align_64 = ArenaAlignAs(64);
|
||||
EXPECT_THAT(align_64.Floor(0), Eq(0));
|
||||
EXPECT_THAT(align_64.Floor(1), Eq(0));
|
||||
EXPECT_THAT(align_64.Floor(63), Eq(0));
|
||||
EXPECT_THAT(align_64.Floor(64), Eq(64));
|
||||
EXPECT_THAT(align_64.Floor(65), Eq(64));
|
||||
EXPECT_THAT(align_64.Floor(127), Eq(64));
|
||||
EXPECT_THAT(align_64.Floor(128), Eq(128));
|
||||
}
|
||||
|
||||
TEST(ArenaAlign, Ceil) {
|
||||
auto align_64 = ArenaAlignAs(64);
|
||||
EXPECT_THAT(align_64.Ceil(0), Eq(0));
|
||||
EXPECT_THAT(align_64.Ceil(1), Eq(64));
|
||||
EXPECT_THAT(align_64.Ceil(63), Eq(64));
|
||||
EXPECT_THAT(align_64.Ceil(64), Eq(64));
|
||||
EXPECT_THAT(align_64.Ceil(65), Eq(128));
|
||||
EXPECT_THAT(align_64.Ceil(127), Eq(128));
|
||||
EXPECT_THAT(align_64.Ceil(128), Eq(128));
|
||||
}
|
||||
|
||||
TEST(ArenaAlign, CeilPtr) {
|
||||
alignas(64) char p[129] = {0};
|
||||
auto align_64 = ArenaAlignAs(64);
|
||||
EXPECT_THAT(align_64.Ceil(p + 0), Eq(p));
|
||||
EXPECT_THAT(align_64.Ceil(p + 1), Eq(p + 64));
|
||||
EXPECT_THAT(align_64.Ceil(p + 63), Eq(p + 64));
|
||||
EXPECT_THAT(align_64.Ceil(p + 64), Eq(p + 64));
|
||||
EXPECT_THAT(align_64.Ceil(p + 65), Eq(p + 128));
|
||||
EXPECT_THAT(align_64.Ceil(p + 127), Eq(p + 128));
|
||||
EXPECT_THAT(align_64.Ceil(p + 128), Eq(p + 128));
|
||||
}
|
||||
|
||||
TEST(ArenaAlign, CheckAligned) {
|
||||
alignas(128) char p[129] = {0};
|
||||
auto align_64 = ArenaAlignAs(64);
|
||||
EXPECT_THAT(align_64.CheckAligned(p + 0), Eq(p));
|
||||
EXPECT_THAT(align_64.CheckAligned(p + 64), Eq(p + 64));
|
||||
EXPECT_THAT(align_64.CheckAligned(p + 128), Eq(p + 128));
|
||||
#ifdef PROTOBUF_HAS_DEATH_TEST
|
||||
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 1), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 7), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 8), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 56), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 63), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 65), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 72), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 120), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 129), ".*");
|
||||
#endif // PROTOBUF_HAS_DEATH_TEST
|
||||
}
|
||||
|
||||
TEST(ArenaAlign, CeilDefaultAligned) {
|
||||
alignas(128) char p[129] = {0};
|
||||
auto align_64 = ArenaAlignAs(64);
|
||||
EXPECT_THAT(align_64.CeilDefaultAligned(p + 0), Eq(p));
|
||||
EXPECT_THAT(align_64.CeilDefaultAligned(p + 8), Eq(p + 64));
|
||||
EXPECT_THAT(align_64.CeilDefaultAligned(p + 56), Eq(p + 64));
|
||||
EXPECT_THAT(align_64.CeilDefaultAligned(p + 64), Eq(p + 64));
|
||||
EXPECT_THAT(align_64.CeilDefaultAligned(p + 72), Eq(p + 128));
|
||||
EXPECT_THAT(align_64.CeilDefaultAligned(p + 120), Eq(p + 128));
|
||||
EXPECT_THAT(align_64.CeilDefaultAligned(p + 128), Eq(p + 128));
|
||||
#ifdef PROTOBUF_HAS_DEATH_TEST
|
||||
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 1), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 7), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 63), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 65), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 127), ".*");
|
||||
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 129), ".*");
|
||||
#endif // PROTOBUF_HAS_DEATH_TEST
|
||||
}
|
||||
|
||||
TEST(ArenaAlign, IsAligned) {
|
||||
auto align_64 = ArenaAlignAs(64);
|
||||
EXPECT_TRUE(align_64.IsAligned(0));
|
||||
EXPECT_FALSE(align_64.IsAligned(1));
|
||||
EXPECT_FALSE(align_64.IsAligned(63));
|
||||
EXPECT_TRUE(align_64.IsAligned(64));
|
||||
EXPECT_FALSE(align_64.IsAligned(65));
|
||||
EXPECT_FALSE(align_64.IsAligned(127));
|
||||
EXPECT_TRUE(align_64.IsAligned(128));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
126
libs/protobuf/src/google/protobuf/arena_allocation_policy.h
Normal file
126
libs/protobuf/src/google/protobuf/arena_allocation_policy.h
Normal file
@@ -0,0 +1,126 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ARENA_ALLOCATION_POLICY_H__
|
||||
#define GOOGLE_PROTOBUF_ARENA_ALLOCATION_POLICY_H__
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "google/protobuf/arena_config.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// `AllocationPolicy` defines `Arena` allocation policies. Applications can
|
||||
// customize the initial and maximum sizes for arena allocation, as well as set
|
||||
// custom allocation and deallocation functions. `AllocationPolicy` is for
|
||||
// protocol buffer internal use only, and typically created from a user facing
|
||||
// public configuration class such as `ArenaOptions`.
|
||||
struct AllocationPolicy {
|
||||
static constexpr size_t kDefaultStartBlockSize = 256;
|
||||
|
||||
size_t start_block_size = kDefaultStartBlockSize;
|
||||
size_t max_block_size = GetDefaultArenaMaxBlockSize();
|
||||
|
||||
void* (*block_alloc)(size_t) = nullptr;
|
||||
void (*block_dealloc)(void*, size_t) = nullptr;
|
||||
|
||||
bool IsDefault() const {
|
||||
return start_block_size == kDefaultStartBlockSize &&
|
||||
max_block_size == GetDefaultArenaMaxBlockSize() &&
|
||||
block_alloc == nullptr && block_dealloc == nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
// Tagged pointer to an AllocationPolicy.
|
||||
class TaggedAllocationPolicyPtr {
|
||||
public:
|
||||
constexpr TaggedAllocationPolicyPtr() : policy_(0) {}
|
||||
|
||||
explicit TaggedAllocationPolicyPtr(AllocationPolicy* policy)
|
||||
: policy_(reinterpret_cast<uintptr_t>(policy)) {}
|
||||
|
||||
void set_policy(AllocationPolicy* policy) {
|
||||
auto bits = policy_ & kTagsMask;
|
||||
policy_ = reinterpret_cast<uintptr_t>(policy) | bits;
|
||||
}
|
||||
|
||||
AllocationPolicy* get() {
|
||||
return reinterpret_cast<AllocationPolicy*>(policy_ & kPtrMask);
|
||||
}
|
||||
const AllocationPolicy* get() const {
|
||||
return reinterpret_cast<const AllocationPolicy*>(policy_ & kPtrMask);
|
||||
}
|
||||
|
||||
AllocationPolicy& operator*() { return *get(); }
|
||||
const AllocationPolicy& operator*() const { return *get(); }
|
||||
|
||||
AllocationPolicy* operator->() { return get(); }
|
||||
const AllocationPolicy* operator->() const { return get(); }
|
||||
|
||||
bool is_user_owned_initial_block() const {
|
||||
return static_cast<bool>(get_mask<kUserOwnedInitialBlock>());
|
||||
}
|
||||
void set_is_user_owned_initial_block(bool v) {
|
||||
set_mask<kUserOwnedInitialBlock>(v);
|
||||
}
|
||||
|
||||
uintptr_t get_raw() const { return policy_; }
|
||||
|
||||
private:
|
||||
enum : uintptr_t {
|
||||
kUserOwnedInitialBlock = 1,
|
||||
};
|
||||
|
||||
static constexpr uintptr_t kTagsMask = 7;
|
||||
static constexpr uintptr_t kPtrMask = ~kTagsMask;
|
||||
|
||||
template <uintptr_t kMask>
|
||||
uintptr_t get_mask() const {
|
||||
return policy_ & kMask;
|
||||
}
|
||||
template <uintptr_t kMask>
|
||||
void set_mask(bool v) {
|
||||
if (v) {
|
||||
policy_ |= kMask;
|
||||
} else {
|
||||
policy_ &= ~kMask;
|
||||
}
|
||||
}
|
||||
uintptr_t policy_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ARENA_ALLOCATION_POLICY_H__
|
||||
189
libs/protobuf/src/google/protobuf/arena_cleanup.h
Normal file
189
libs/protobuf/src/google/protobuf/arena_cleanup.h
Normal file
@@ -0,0 +1,189 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ARENA_CLEANUP_H__
|
||||
#define GOOGLE_PROTOBUF_ARENA_CLEANUP_H__
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "google/protobuf/stubs/logging.h"
|
||||
#include "google/protobuf/stubs/common.h"
|
||||
#include "absl/base/attributes.h"
|
||||
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
namespace cleanup {
|
||||
|
||||
// Helper function invoking the destructor of `object`
|
||||
template <typename T>
|
||||
void arena_destruct_object(void* object) {
|
||||
reinterpret_cast<T*>(object)->~T();
|
||||
}
|
||||
|
||||
// Tag defines the type of cleanup / cleanup object. This tag is stored in the
|
||||
// lowest 2 bits of the `elem` value identifying the type of node. All node
|
||||
// types must start with a `uintptr_t` that stores `Tag` in its low two bits.
|
||||
enum class Tag : uintptr_t {
|
||||
kDynamic = 0, // DynamicNode
|
||||
kString = 1, // StringNode (std::string)
|
||||
};
|
||||
|
||||
// DynamicNode contains the object (`elem`) that needs to be
|
||||
// destroyed, and the function to destroy it (`destructor`)
|
||||
// elem must be aligned at minimum on a 4 byte boundary.
|
||||
struct DynamicNode {
|
||||
uintptr_t elem;
|
||||
void (*destructor)(void*);
|
||||
};
|
||||
|
||||
// StringNode contains a `std::string` object (`elem`) that needs to be
|
||||
// destroyed. The lowest 2 bits of `elem` contain the non-zero kString tag.
|
||||
struct StringNode {
|
||||
uintptr_t elem;
|
||||
};
|
||||
|
||||
|
||||
// EnableSpecializedTags() return true if the alignment of tagged objects
|
||||
// such as std::string allow us to poke tags in the 2 LSB bits.
|
||||
inline constexpr bool EnableSpecializedTags() {
|
||||
// For now we require 2 bits
|
||||
return alignof(std::string) >= 8;
|
||||
}
|
||||
|
||||
// Adds a cleanup entry identified by `tag` at memory location `pos`.
|
||||
inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CreateNode(Tag tag, void* pos,
|
||||
const void* elem_raw,
|
||||
void (*destructor)(void*)) {
|
||||
auto elem = reinterpret_cast<uintptr_t>(elem_raw);
|
||||
if (EnableSpecializedTags()) {
|
||||
GOOGLE_DCHECK_EQ(elem & 3, 0ULL); // Must be aligned
|
||||
switch (tag) {
|
||||
case Tag::kString: {
|
||||
StringNode n = {elem | static_cast<uintptr_t>(Tag::kString)};
|
||||
memcpy(pos, &n, sizeof(n));
|
||||
return;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
DynamicNode n = {elem, destructor};
|
||||
memcpy(pos, &n, sizeof(n));
|
||||
}
|
||||
|
||||
// Optimization: performs a prefetch on `elem_address`.
|
||||
inline ABSL_ATTRIBUTE_ALWAYS_INLINE void PrefetchNode(
|
||||
const void* elem_address) {
|
||||
(void)elem_address;
|
||||
}
|
||||
|
||||
// Destroys the node idenitfied by `tag` stored at memory location `pos`.
|
||||
inline ABSL_ATTRIBUTE_ALWAYS_INLINE void DestroyNode(Tag tag, const void* pos) {
|
||||
if (EnableSpecializedTags()) {
|
||||
switch (tag) {
|
||||
case Tag::kString: {
|
||||
StringNode n;
|
||||
memcpy(&n, pos, sizeof(n));
|
||||
auto* s = reinterpret_cast<std::string*>(n.elem & ~0x7ULL);
|
||||
// Some compilers don't like fully qualified explicit dtor calls,
|
||||
// so use an alias to avoid having to type `::`.
|
||||
using string_type = std::string;
|
||||
s->~string_type();
|
||||
return;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
DynamicNode n;
|
||||
memcpy(&n, pos, sizeof(n));
|
||||
n.destructor(reinterpret_cast<void*>(n.elem));
|
||||
}
|
||||
|
||||
// Returns the `tag` identifying the type of object for `destructor` or
|
||||
// kDynamic if `destructor` does not identify a well know object type.
|
||||
inline ABSL_ATTRIBUTE_ALWAYS_INLINE Tag Type(void (*destructor)(void*)) {
|
||||
if (EnableSpecializedTags()) {
|
||||
if (destructor == &arena_destruct_object<std::string>) {
|
||||
return Tag::kString;
|
||||
}
|
||||
}
|
||||
return Tag::kDynamic;
|
||||
}
|
||||
|
||||
// Returns the `tag` identifying the type of object stored at memory location
|
||||
// `elem`, which represents the first uintptr_t value in the node.
|
||||
inline ABSL_ATTRIBUTE_ALWAYS_INLINE Tag Type(void* raw) {
|
||||
if (!EnableSpecializedTags()) return Tag::kDynamic;
|
||||
|
||||
uintptr_t elem;
|
||||
memcpy(&elem, raw, sizeof(elem));
|
||||
switch (static_cast<Tag>(elem & 0x7ULL)) {
|
||||
case Tag::kDynamic:
|
||||
return Tag::kDynamic;
|
||||
case Tag::kString:
|
||||
return Tag::kString;
|
||||
default:
|
||||
GOOGLE_LOG(FATAL) << "Corrupted cleanup tag: " << (elem & 0x7ULL);
|
||||
return Tag::kDynamic;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the required size in bytes off the node type identified by `tag`.
|
||||
inline ABSL_ATTRIBUTE_ALWAYS_INLINE size_t Size(Tag tag) {
|
||||
if (!EnableSpecializedTags()) return sizeof(DynamicNode);
|
||||
|
||||
switch (tag) {
|
||||
case Tag::kDynamic:
|
||||
return sizeof(DynamicNode);
|
||||
case Tag::kString:
|
||||
return sizeof(StringNode);
|
||||
default:
|
||||
GOOGLE_LOG(FATAL) << "Corrupted cleanup tag: " << static_cast<int>(tag);
|
||||
return sizeof(DynamicNode);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the required size in bytes off the node type for `destructor`.
|
||||
inline ABSL_ATTRIBUTE_ALWAYS_INLINE size_t Size(void (*destructor)(void*)) {
|
||||
return destructor == nullptr ? 0 : Size(Type(destructor));
|
||||
}
|
||||
|
||||
} // namespace cleanup
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ARENA_CLEANUP_H__
|
||||
53
libs/protobuf/src/google/protobuf/arena_config.cc
Normal file
53
libs/protobuf/src/google/protobuf/arena_config.cc
Normal file
@@ -0,0 +1,53 @@
|
||||
// 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/arena_config.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
PROTOBUF_CONSTINIT const size_t kDefaultDefaultArenaMaxBlockSize = 8 << 10;
|
||||
|
||||
namespace arena_config_internal {
|
||||
|
||||
std::atomic<size_t> default_arena_max_block_size{
|
||||
kDefaultDefaultArenaMaxBlockSize};
|
||||
|
||||
} // namespace arena_config_internal
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
73
libs/protobuf/src/google/protobuf/arena_config.h
Normal file
73
libs/protobuf/src/google/protobuf/arena_config.h
Normal file
@@ -0,0 +1,73 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ARENA_CONFIG_H__
|
||||
#define GOOGLE_PROTOBUF_ARENA_CONFIG_H__
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
namespace arena_config_internal {
|
||||
|
||||
// We use an atomic here only for correctness so that we can read/write
|
||||
// concurrently. We don't have memory order requirements so we use relaxed
|
||||
// memory ordering.
|
||||
PROTOBUF_EXPORT extern std::atomic<size_t> default_arena_max_block_size;
|
||||
|
||||
} // namespace arena_config_internal
|
||||
|
||||
// The default value to use for DefaultArenaMaxBlockSize when
|
||||
// SetDefaultArenaMaxBlockSize hasn't been called.
|
||||
PROTOBUF_EXPORT extern const size_t kDefaultDefaultArenaMaxBlockSize;
|
||||
|
||||
// The default value to use for arena max block size when no value is provided
|
||||
// in ArenaOptions.
|
||||
inline size_t GetDefaultArenaMaxBlockSize() {
|
||||
return arena_config_internal::default_arena_max_block_size.load(
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
inline void SetDefaultArenaMaxBlockSize(size_t default_arena_max_block_size) {
|
||||
return arena_config_internal::default_arena_max_block_size.store(
|
||||
default_arena_max_block_size, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ARENA_CONFIG_H__
|
||||
694
libs/protobuf/src/google/protobuf/arena_impl.h
Normal file
694
libs/protobuf/src/google/protobuf/arena_impl.h
Normal file
@@ -0,0 +1,694 @@
|
||||
// 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.
|
||||
|
||||
// This file defines an Arena allocator for better allocation performance.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ARENA_IMPL_H__
|
||||
#define GOOGLE_PROTOBUF_ARENA_IMPL_H__
|
||||
|
||||
#include <atomic>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "google/protobuf/stubs/common.h"
|
||||
#include "google/protobuf/stubs/logging.h"
|
||||
#include "absl/numeric/bits.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "google/protobuf/arena_allocation_policy.h"
|
||||
#include "google/protobuf/arena_cleanup.h"
|
||||
#include "google/protobuf/arena_config.h"
|
||||
#include "google/protobuf/arenaz_sampler.h"
|
||||
#include "google/protobuf/port.h"
|
||||
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// To prevent sharing cache lines between threads
|
||||
#ifdef __cpp_aligned_new
|
||||
enum { kCacheAlignment = 64 };
|
||||
#else
|
||||
enum { kCacheAlignment = alignof(max_align_t) }; // do the best we can
|
||||
#endif
|
||||
|
||||
inline PROTOBUF_ALWAYS_INLINE constexpr size_t AlignUpTo8(size_t n) {
|
||||
// Align n to next multiple of 8 (from Hacker's Delight, Chapter 3.)
|
||||
return (n + 7) & static_cast<size_t>(-8);
|
||||
}
|
||||
|
||||
inline PROTOBUF_ALWAYS_INLINE constexpr size_t AlignUpTo(size_t n, size_t a) {
|
||||
// We are wasting space by over allocating align - 8 bytes. Compared to a
|
||||
// dedicated function that takes current alignment in consideration. Such a
|
||||
// scheme would only waste (align - 8)/2 bytes on average, but requires a
|
||||
// dedicated function in the outline arena allocation functions. Possibly
|
||||
// re-evaluate tradeoffs later.
|
||||
return a <= 8 ? AlignUpTo8(n) : n + a - 8;
|
||||
}
|
||||
|
||||
inline PROTOBUF_ALWAYS_INLINE void* AlignTo(void* p, size_t a) {
|
||||
if (a <= 8) {
|
||||
return p;
|
||||
} else {
|
||||
auto u = reinterpret_cast<uintptr_t>(p);
|
||||
return reinterpret_cast<void*>((u + a - 1) & (~a + 1));
|
||||
}
|
||||
}
|
||||
|
||||
// Arena blocks are variable length malloc-ed objects. The following structure
|
||||
// describes the common header for all blocks.
|
||||
struct ArenaBlock {
|
||||
// For the sentry block with zero-size where ptr_, limit_, cleanup_nodes all
|
||||
// point to "this".
|
||||
constexpr ArenaBlock()
|
||||
: next(nullptr), cleanup_nodes(this), size(0) {}
|
||||
|
||||
ArenaBlock(ArenaBlock* next, size_t size)
|
||||
: next(next), cleanup_nodes(nullptr), size(size) {
|
||||
GOOGLE_DCHECK_GT(size, sizeof(ArenaBlock));
|
||||
}
|
||||
|
||||
char* Pointer(size_t n) {
|
||||
GOOGLE_DCHECK_LE(n, size);
|
||||
return reinterpret_cast<char*>(this) + n;
|
||||
}
|
||||
char* Limit() { return Pointer(size & static_cast<size_t>(-8)); }
|
||||
|
||||
bool IsSentry() const { return size == 0; }
|
||||
|
||||
ArenaBlock* const next;
|
||||
void* cleanup_nodes;
|
||||
const size_t size;
|
||||
// data follows
|
||||
};
|
||||
|
||||
using LifecycleIdAtomic = uint64_t;
|
||||
|
||||
// MetricsCollector collects stats for a particular arena.
|
||||
class PROTOBUF_EXPORT ArenaMetricsCollector {
|
||||
public:
|
||||
ArenaMetricsCollector(bool record_allocs) : record_allocs_(record_allocs) {}
|
||||
|
||||
// Invoked when the arena is about to be destroyed. This method will
|
||||
// typically finalize any metric collection and delete the collector.
|
||||
// space_allocated is the space used by the arena.
|
||||
virtual void OnDestroy(uint64_t space_allocated) = 0;
|
||||
|
||||
// OnReset() is called when the associated arena is reset.
|
||||
// space_allocated is the space used by the arena just before the reset.
|
||||
virtual void OnReset(uint64_t space_allocated) = 0;
|
||||
|
||||
// OnAlloc is called when an allocation happens.
|
||||
// type_info is promised to be static - its lifetime extends to
|
||||
// match program's lifetime (It is given by typeid operator).
|
||||
// Note: typeid(void) will be passed as allocated_type every time we
|
||||
// intentionally want to avoid monitoring an allocation. (i.e. internal
|
||||
// allocations for managing the arena)
|
||||
virtual void OnAlloc(const std::type_info* allocated_type,
|
||||
uint64_t alloc_size) = 0;
|
||||
|
||||
// Does OnAlloc() need to be called? If false, metric collection overhead
|
||||
// will be reduced since we will not do extra work per allocation.
|
||||
bool RecordAllocs() { return record_allocs_; }
|
||||
|
||||
protected:
|
||||
// This class is destructed by the call to OnDestroy().
|
||||
~ArenaMetricsCollector() = default;
|
||||
const bool record_allocs_;
|
||||
};
|
||||
|
||||
enum class AllocationClient { kDefault, kArray };
|
||||
|
||||
class ThreadSafeArena;
|
||||
|
||||
// Tag type used to invoke the constructor of the first SerialArena.
|
||||
struct FirstSerialArena {
|
||||
explicit FirstSerialArena() = default;
|
||||
};
|
||||
|
||||
// A simple arena allocator. Calls to allocate functions must be properly
|
||||
// serialized by the caller, hence this class cannot be used as a general
|
||||
// purpose allocator in a multi-threaded program. It serves as a building block
|
||||
// for ThreadSafeArena, which provides a thread-safe arena allocator.
|
||||
//
|
||||
// This class manages
|
||||
// 1) Arena bump allocation + owning memory blocks.
|
||||
// 2) Maintaining a cleanup list.
|
||||
// It delegates the actual memory allocation back to ThreadSafeArena, which
|
||||
// contains the information on block growth policy and backing memory allocation
|
||||
// used.
|
||||
class PROTOBUF_EXPORT SerialArena {
|
||||
public:
|
||||
struct Memory {
|
||||
void* ptr;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
void CleanupList();
|
||||
uint64_t SpaceAllocated() const {
|
||||
return space_allocated_.load(std::memory_order_relaxed);
|
||||
}
|
||||
uint64_t SpaceUsed() const;
|
||||
|
||||
bool HasSpace(size_t n) const {
|
||||
return n <= static_cast<size_t>(limit_ - ptr());
|
||||
}
|
||||
|
||||
// See comments on `cached_blocks_` member for details.
|
||||
PROTOBUF_ALWAYS_INLINE void* TryAllocateFromCachedBlock(size_t size) {
|
||||
if (PROTOBUF_PREDICT_FALSE(size < 16)) return nullptr;
|
||||
// We round up to the next larger block in case the memory doesn't match
|
||||
// the pattern we are looking for.
|
||||
const size_t index = absl::bit_width(size - 1) - 4;
|
||||
|
||||
if (index >= cached_block_length_) return nullptr;
|
||||
auto& cached_head = cached_blocks_[index];
|
||||
if (cached_head == nullptr) return nullptr;
|
||||
|
||||
void* ret = cached_head;
|
||||
PROTOBUF_UNPOISON_MEMORY_REGION(ret, size);
|
||||
cached_head = cached_head->next;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// In kArray mode we look through cached blocks.
|
||||
// We do not do this by default because most non-array allocations will not
|
||||
// have the right size and will fail to find an appropriate cached block.
|
||||
//
|
||||
// TODO(sbenza): Evaluate if we should use cached blocks for message types of
|
||||
// the right size. We can statically know if the allocation size can benefit
|
||||
// from it.
|
||||
template <AllocationClient alloc_client = AllocationClient::kDefault>
|
||||
void* AllocateAligned(size_t n) {
|
||||
GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n); // Must be already aligned.
|
||||
GOOGLE_DCHECK_GE(limit_, ptr());
|
||||
|
||||
if (alloc_client == AllocationClient::kArray) {
|
||||
if (void* res = TryAllocateFromCachedBlock(n)) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
if (PROTOBUF_PREDICT_FALSE(!HasSpace(n))) {
|
||||
return AllocateAlignedFallback(n);
|
||||
}
|
||||
return AllocateFromExisting(n);
|
||||
}
|
||||
|
||||
private:
|
||||
void* AllocateFromExisting(size_t n) {
|
||||
PROTOBUF_UNPOISON_MEMORY_REGION(ptr(), n);
|
||||
void* ret = ptr();
|
||||
set_ptr(static_cast<char*>(ret) + n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// See comments on `cached_blocks_` member for details.
|
||||
void ReturnArrayMemory(void* p, size_t size) {
|
||||
// We only need to check for 32-bit platforms.
|
||||
// In 64-bit platforms the minimum allocation size from Repeated*Field will
|
||||
// be 16 guaranteed.
|
||||
if (sizeof(void*) < 8) {
|
||||
if (PROTOBUF_PREDICT_FALSE(size < 16)) return;
|
||||
} else {
|
||||
PROTOBUF_ASSUME(size >= 16);
|
||||
}
|
||||
|
||||
// We round down to the next smaller block in case the memory doesn't match
|
||||
// the pattern we are looking for. eg, someone might have called Reserve()
|
||||
// on the repeated field.
|
||||
const size_t index = absl::bit_width(size) - 5;
|
||||
|
||||
if (PROTOBUF_PREDICT_FALSE(index >= cached_block_length_)) {
|
||||
// We can't put this object on the freelist so make this object the
|
||||
// freelist. It is guaranteed it is larger than the one we have, and
|
||||
// large enough to hold another allocation of `size`.
|
||||
CachedBlock** new_list = static_cast<CachedBlock**>(p);
|
||||
size_t new_size = size / sizeof(CachedBlock*);
|
||||
|
||||
std::copy(cached_blocks_, cached_blocks_ + cached_block_length_,
|
||||
new_list);
|
||||
|
||||
// We need to unpoison this memory before filling it in case it has been
|
||||
// poisoned by another santizer client.
|
||||
PROTOBUF_UNPOISON_MEMORY_REGION(
|
||||
new_list + cached_block_length_,
|
||||
(new_size - cached_block_length_) * sizeof(CachedBlock*));
|
||||
|
||||
std::fill(new_list + cached_block_length_, new_list + new_size, nullptr);
|
||||
|
||||
cached_blocks_ = new_list;
|
||||
// Make the size fit in uint8_t. This is the power of two, so we don't
|
||||
// need anything larger.
|
||||
cached_block_length_ =
|
||||
static_cast<uint8_t>(std::min(size_t{64}, new_size));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto& cached_head = cached_blocks_[index];
|
||||
auto* new_node = static_cast<CachedBlock*>(p);
|
||||
new_node->next = cached_head;
|
||||
cached_head = new_node;
|
||||
PROTOBUF_POISON_MEMORY_REGION(p, size);
|
||||
}
|
||||
|
||||
public:
|
||||
// Allocate space if the current region provides enough space.
|
||||
bool MaybeAllocateAligned(size_t n, void** out) {
|
||||
GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n); // Must be already aligned.
|
||||
GOOGLE_DCHECK_GE(limit_, ptr());
|
||||
if (PROTOBUF_PREDICT_FALSE(!HasSpace(n))) return false;
|
||||
*out = AllocateFromExisting(n);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If there is enough space in the current block, allocate space for one `T`
|
||||
// object and register for destruction. The object has not been constructed
|
||||
// and the memory returned is uninitialized.
|
||||
template <typename T>
|
||||
PROTOBUF_ALWAYS_INLINE void* MaybeAllocateWithCleanup() {
|
||||
GOOGLE_DCHECK_GE(limit_, ptr());
|
||||
static_assert(!std::is_trivially_destructible<T>::value,
|
||||
"This function is only for non-trivial types.");
|
||||
|
||||
constexpr int aligned_size = AlignUpTo8(sizeof(T));
|
||||
constexpr auto destructor = cleanup::arena_destruct_object<T>;
|
||||
size_t required = aligned_size + cleanup::Size(destructor);
|
||||
if (PROTOBUF_PREDICT_FALSE(!HasSpace(required))) {
|
||||
return nullptr;
|
||||
}
|
||||
void* ptr = AllocateFromExistingWithCleanupFallback(aligned_size,
|
||||
alignof(T), destructor);
|
||||
PROTOBUF_ASSUME(ptr != nullptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
PROTOBUF_ALWAYS_INLINE
|
||||
void* AllocateAlignedWithCleanup(size_t n, size_t align,
|
||||
void (*destructor)(void*)) {
|
||||
size_t required = AlignUpTo(n, align) + cleanup::Size(destructor);
|
||||
if (PROTOBUF_PREDICT_FALSE(!HasSpace(required))) {
|
||||
return AllocateAlignedWithCleanupFallback(n, align, destructor);
|
||||
}
|
||||
return AllocateFromExistingWithCleanupFallback(n, align, destructor);
|
||||
}
|
||||
|
||||
PROTOBUF_ALWAYS_INLINE
|
||||
void AddCleanup(void* elem, void (*destructor)(void*)) {
|
||||
size_t required = cleanup::Size(destructor);
|
||||
if (PROTOBUF_PREDICT_FALSE(!HasSpace(required))) {
|
||||
return AddCleanupFallback(elem, destructor);
|
||||
}
|
||||
AddCleanupFromExisting(elem, destructor);
|
||||
}
|
||||
|
||||
private:
|
||||
void* AllocateFromExistingWithCleanupFallback(size_t n, size_t align,
|
||||
void (*destructor)(void*)) {
|
||||
n = AlignUpTo(n, align);
|
||||
PROTOBUF_UNPOISON_MEMORY_REGION(ptr(), n);
|
||||
void* ret = internal::AlignTo(ptr(), align);
|
||||
set_ptr(ptr() + n);
|
||||
GOOGLE_DCHECK_GE(limit_, ptr());
|
||||
AddCleanupFromExisting(ret, destructor);
|
||||
return ret;
|
||||
}
|
||||
|
||||
PROTOBUF_ALWAYS_INLINE
|
||||
void AddCleanupFromExisting(void* elem, void (*destructor)(void*)) {
|
||||
cleanup::Tag tag = cleanup::Type(destructor);
|
||||
size_t n = cleanup::Size(tag);
|
||||
|
||||
PROTOBUF_UNPOISON_MEMORY_REGION(limit_ - n, n);
|
||||
limit_ -= n;
|
||||
GOOGLE_DCHECK_GE(limit_, ptr());
|
||||
cleanup::CreateNode(tag, limit_, elem, destructor);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ThreadSafeArena;
|
||||
|
||||
// Creates a new SerialArena inside mem using the remaining memory as for
|
||||
// future allocations.
|
||||
// The `parent` arena must outlive the serial arena, which is guaranteed
|
||||
// because the parent manages the lifetime of the serial arenas.
|
||||
static SerialArena* New(SerialArena::Memory mem, ThreadSafeArena& parent);
|
||||
// Free SerialArena returning the memory passed in to New
|
||||
template <typename Deallocator>
|
||||
Memory Free(Deallocator deallocator);
|
||||
|
||||
// Members are declared here to track sizeof(SerialArena) and hotness
|
||||
// centrally. They are (roughly) laid out in descending order of hotness.
|
||||
|
||||
// Next pointer to allocate from. Always 8-byte aligned. Points inside
|
||||
// head_ (and head_->pos will always be non-canonical). We keep these
|
||||
// here to reduce indirection.
|
||||
std::atomic<char*> ptr_{nullptr};
|
||||
// Limiting address up to which memory can be allocated from the head block.
|
||||
char* limit_ = nullptr;
|
||||
|
||||
std::atomic<ArenaBlock*> head_{nullptr}; // Head of linked list of blocks.
|
||||
std::atomic<size_t> space_used_{0}; // Necessary for metrics.
|
||||
std::atomic<size_t> space_allocated_{0};
|
||||
ThreadSafeArena& parent_;
|
||||
|
||||
// Repeated*Field and Arena play together to reduce memory consumption by
|
||||
// reusing blocks. Currently, natural growth of the repeated field types makes
|
||||
// them allocate blocks of size `8 + 2^N, N>=3`.
|
||||
// When the repeated field grows returns the previous block and we put it in
|
||||
// this free list.
|
||||
// `cached_blocks_[i]` points to the free list for blocks of size `8+2^(i+3)`.
|
||||
// The array of freelists is grown when needed in `ReturnArrayMemory()`.
|
||||
struct CachedBlock {
|
||||
// Simple linked list.
|
||||
CachedBlock* next;
|
||||
};
|
||||
uint8_t cached_block_length_ = 0;
|
||||
CachedBlock** cached_blocks_ = nullptr;
|
||||
|
||||
// Helper getters/setters to handle relaxed operations on atomic variables.
|
||||
ArenaBlock* head() { return head_.load(std::memory_order_relaxed); }
|
||||
const ArenaBlock* head() const {
|
||||
return head_.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
char* ptr() { return ptr_.load(std::memory_order_relaxed); }
|
||||
const char* ptr() const { return ptr_.load(std::memory_order_relaxed); }
|
||||
void set_ptr(char* ptr) { return ptr_.store(ptr, std::memory_order_relaxed); }
|
||||
|
||||
// Constructor is private as only New() should be used.
|
||||
inline SerialArena(ArenaBlock* b, ThreadSafeArena& parent);
|
||||
|
||||
// Constructors to handle the first SerialArena.
|
||||
inline explicit SerialArena(ThreadSafeArena& parent);
|
||||
inline SerialArena(FirstSerialArena, ArenaBlock* b, ThreadSafeArena& parent);
|
||||
|
||||
void* AllocateAlignedFallback(size_t n);
|
||||
void* AllocateAlignedWithCleanupFallback(size_t n, size_t align,
|
||||
void (*destructor)(void*));
|
||||
void AddCleanupFallback(void* elem, void (*destructor)(void*));
|
||||
inline void AllocateNewBlock(size_t n);
|
||||
inline void Init(ArenaBlock* b, size_t offset);
|
||||
|
||||
public:
|
||||
static constexpr size_t kBlockHeaderSize = AlignUpTo8(sizeof(ArenaBlock));
|
||||
};
|
||||
|
||||
// Tag type used to invoke the constructor of message-owned arena.
|
||||
// Only message-owned arenas use this constructor for creation.
|
||||
// Such constructors are internal implementation details of the library.
|
||||
struct MessageOwned {
|
||||
explicit MessageOwned() = default;
|
||||
};
|
||||
|
||||
// This class provides the core Arena memory allocation library. Different
|
||||
// implementations only need to implement the public interface below.
|
||||
// Arena is not a template type as that would only be useful if all protos
|
||||
// in turn would be templates, which will/cannot happen. However separating
|
||||
// the memory allocation part from the cruft of the API users expect we can
|
||||
// use #ifdef the select the best implementation based on hardware / OS.
|
||||
class PROTOBUF_EXPORT ThreadSafeArena {
|
||||
public:
|
||||
ThreadSafeArena();
|
||||
|
||||
// Constructor solely used by message-owned arena.
|
||||
explicit ThreadSafeArena(internal::MessageOwned);
|
||||
|
||||
ThreadSafeArena(char* mem, size_t size);
|
||||
|
||||
explicit ThreadSafeArena(void* mem, size_t size,
|
||||
const AllocationPolicy& policy);
|
||||
|
||||
// All protos have pointers back to the arena hence Arena must have
|
||||
// pointer stability.
|
||||
ThreadSafeArena(const ThreadSafeArena&) = delete;
|
||||
ThreadSafeArena& operator=(const ThreadSafeArena&) = delete;
|
||||
ThreadSafeArena(ThreadSafeArena&&) = delete;
|
||||
ThreadSafeArena& operator=(ThreadSafeArena&&) = delete;
|
||||
|
||||
// Destructor deletes all owned heap allocated objects, and destructs objects
|
||||
// that have non-trivial destructors, except for proto2 message objects whose
|
||||
// destructors can be skipped. Also, frees all blocks except the initial block
|
||||
// if it was passed in.
|
||||
~ThreadSafeArena();
|
||||
|
||||
uint64_t Reset();
|
||||
|
||||
uint64_t SpaceAllocated() const;
|
||||
uint64_t SpaceUsed() const;
|
||||
|
||||
template <AllocationClient alloc_client = AllocationClient::kDefault>
|
||||
void* AllocateAligned(size_t n) {
|
||||
SerialArena* arena;
|
||||
if (PROTOBUF_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
|
||||
return arena->AllocateAligned<alloc_client>(n);
|
||||
} else {
|
||||
return AllocateAlignedFallback<alloc_client>(n);
|
||||
}
|
||||
}
|
||||
|
||||
void ReturnArrayMemory(void* p, size_t size) {
|
||||
SerialArena* arena;
|
||||
if (PROTOBUF_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
|
||||
arena->ReturnArrayMemory(p, size);
|
||||
}
|
||||
}
|
||||
|
||||
// This function allocates n bytes if the common happy case is true and
|
||||
// returns true. Otherwise does nothing and returns false. This strange
|
||||
// semantics is necessary to allow callers to program functions that only
|
||||
// have fallback function calls in tail position. This substantially improves
|
||||
// code for the happy path.
|
||||
PROTOBUF_NDEBUG_INLINE bool MaybeAllocateAligned(size_t n, void** out) {
|
||||
SerialArena* arena;
|
||||
if (PROTOBUF_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
|
||||
return arena->MaybeAllocateAligned(n, out);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void* AllocateAlignedWithCleanup(size_t n, size_t align,
|
||||
void (*destructor)(void*));
|
||||
|
||||
// Add object pointer and cleanup function pointer to the list.
|
||||
void AddCleanup(void* elem, void (*cleanup)(void*));
|
||||
|
||||
// Checks whether this arena is message-owned.
|
||||
PROTOBUF_ALWAYS_INLINE bool IsMessageOwned() const {
|
||||
return tag_and_id_ & kMessageOwnedArena;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ArenaBenchmark;
|
||||
friend class TcParser;
|
||||
friend class SerialArena;
|
||||
friend struct SerialArenaChunkHeader;
|
||||
static uint64_t GetNextLifeCycleId();
|
||||
|
||||
class SerialArenaChunk;
|
||||
|
||||
// Returns a new SerialArenaChunk that has {id, serial} at slot 0. It may
|
||||
// grow based on "prev_num_slots".
|
||||
static SerialArenaChunk* NewSerialArenaChunk(uint32_t prev_capacity, void* id,
|
||||
SerialArena* serial);
|
||||
static SerialArenaChunk* SentrySerialArenaChunk();
|
||||
|
||||
// Returns the first ArenaBlock* for the first SerialArena. If users provide
|
||||
// one, use it if it's acceptable. Otherwise returns a sentry block.
|
||||
ArenaBlock* FirstBlock(void* buf, size_t size);
|
||||
// Same as the above but returns a valid block if "policy" is not default.
|
||||
ArenaBlock* FirstBlock(void* buf, size_t size,
|
||||
const AllocationPolicy& policy);
|
||||
|
||||
// Adds SerialArena to the chunked list. May create a new chunk.
|
||||
void AddSerialArena(void* id, SerialArena* serial);
|
||||
|
||||
// Members are declared here to track sizeof(ThreadSafeArena) and hotness
|
||||
// centrally.
|
||||
|
||||
// Unique for each arena. Changes on Reset().
|
||||
uint64_t tag_and_id_ = 0;
|
||||
|
||||
TaggedAllocationPolicyPtr alloc_policy_; // Tagged pointer to AllocPolicy.
|
||||
ThreadSafeArenaStatsHandle arena_stats_;
|
||||
|
||||
// Adding a new chunk to head_ must be protected by mutex_.
|
||||
absl::Mutex mutex_;
|
||||
// Pointer to a linked list of SerialArenaChunk.
|
||||
std::atomic<SerialArenaChunk*> head_{nullptr};
|
||||
|
||||
void* first_owner_;
|
||||
// Must be declared after alloc_policy_; otherwise, it may lose info on
|
||||
// user-provided initial block.
|
||||
SerialArena first_arena_;
|
||||
|
||||
// The LSB of tag_and_id_ indicates if the arena is message-owned.
|
||||
enum : uint64_t { kMessageOwnedArena = 1 };
|
||||
|
||||
static_assert(std::is_trivially_destructible<SerialArena>{},
|
||||
"SerialArena needs to be trivially destructible.");
|
||||
|
||||
const AllocationPolicy* AllocPolicy() const { return alloc_policy_.get(); }
|
||||
void InitializeWithPolicy(const AllocationPolicy& policy);
|
||||
void* AllocateAlignedWithCleanupFallback(size_t n, size_t align,
|
||||
void (*destructor)(void*));
|
||||
|
||||
void Init();
|
||||
|
||||
// Delete or Destruct all objects owned by the arena.
|
||||
void CleanupList();
|
||||
|
||||
inline void CacheSerialArena(SerialArena* serial) {
|
||||
if (!IsMessageOwned()) {
|
||||
thread_cache().last_serial_arena = serial;
|
||||
thread_cache().last_lifecycle_id_seen = tag_and_id_;
|
||||
}
|
||||
}
|
||||
|
||||
PROTOBUF_NDEBUG_INLINE bool GetSerialArenaFast(SerialArena** arena) {
|
||||
// If this thread already owns a block in this arena then try to use that.
|
||||
// This fast path optimizes the case where multiple threads allocate from
|
||||
// the same arena.
|
||||
ThreadCache* tc = &thread_cache();
|
||||
if (PROTOBUF_PREDICT_TRUE(tc->last_lifecycle_id_seen == tag_and_id_)) {
|
||||
*arena = tc->last_serial_arena;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Finds SerialArena or creates one if not found. When creating a new one,
|
||||
// create a big enough block to accommodate n bytes.
|
||||
SerialArena* GetSerialArenaFallback(size_t n);
|
||||
|
||||
template <AllocationClient alloc_client = AllocationClient::kDefault>
|
||||
void* AllocateAlignedFallback(size_t n);
|
||||
|
||||
// Executes callback function over SerialArenaChunk. Passes const
|
||||
// SerialArenaChunk*.
|
||||
template <typename Functor>
|
||||
void WalkConstSerialArenaChunk(Functor fn) const;
|
||||
|
||||
// Executes callback function over SerialArenaChunk.
|
||||
template <typename Functor>
|
||||
void WalkSerialArenaChunk(Functor fn);
|
||||
|
||||
// Executes callback function over SerialArena in chunked list in reverse
|
||||
// chronological order. Passes const SerialArena*.
|
||||
template <typename Functor>
|
||||
void PerConstSerialArenaInChunk(Functor fn) const;
|
||||
|
||||
// Releases all memory except the first block which it returns. The first
|
||||
// block might be owned by the user and thus need some extra checks before
|
||||
// deleting.
|
||||
SerialArena::Memory Free(size_t* space_allocated);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4324)
|
||||
#endif
|
||||
struct alignas(kCacheAlignment) ThreadCache {
|
||||
#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
|
||||
// If we are using the ThreadLocalStorage class to store the ThreadCache,
|
||||
// then the ThreadCache's default constructor has to be responsible for
|
||||
// initializing it.
|
||||
ThreadCache()
|
||||
: next_lifecycle_id(0),
|
||||
last_lifecycle_id_seen(-1),
|
||||
last_serial_arena(nullptr) {}
|
||||
#endif
|
||||
|
||||
// Number of per-thread lifecycle IDs to reserve. Must be power of two.
|
||||
// To reduce contention on a global atomic, each thread reserves a batch of
|
||||
// IDs. The following number is calculated based on a stress test with
|
||||
// ~6500 threads all frequently allocating a new arena.
|
||||
static constexpr size_t kPerThreadIds = 256;
|
||||
// Next lifecycle ID available to this thread. We need to reserve a new
|
||||
// batch, if `next_lifecycle_id & (kPerThreadIds - 1) == 0`.
|
||||
uint64_t next_lifecycle_id;
|
||||
// The ThreadCache is considered valid as long as this matches the
|
||||
// lifecycle_id of the arena being used.
|
||||
uint64_t last_lifecycle_id_seen;
|
||||
SerialArena* last_serial_arena;
|
||||
};
|
||||
|
||||
// Lifecycle_id can be highly contended variable in a situation of lots of
|
||||
// arena creation. Make sure that other global variables are not sharing the
|
||||
// cacheline.
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4324)
|
||||
#endif
|
||||
struct alignas(kCacheAlignment) CacheAlignedLifecycleIdGenerator {
|
||||
constexpr CacheAlignedLifecycleIdGenerator() : id{0} {}
|
||||
|
||||
std::atomic<LifecycleIdAtomic> id;
|
||||
};
|
||||
static CacheAlignedLifecycleIdGenerator lifecycle_id_generator_;
|
||||
#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
|
||||
// iOS does not support __thread keyword so we use a custom thread local
|
||||
// storage class we implemented.
|
||||
static ThreadCache& thread_cache();
|
||||
#elif defined(PROTOBUF_USE_DLLS)
|
||||
// Thread local variables cannot be exposed through DLL interface but we can
|
||||
// wrap them in static functions.
|
||||
static ThreadCache& thread_cache();
|
||||
#else
|
||||
static PROTOBUF_THREAD_LOCAL ThreadCache thread_cache_;
|
||||
static ThreadCache& thread_cache() { return thread_cache_; }
|
||||
#endif
|
||||
|
||||
public:
|
||||
// kBlockHeaderSize is sizeof(ArenaBlock), aligned up to the nearest multiple
|
||||
// of 8 to protect the invariant that pos is always at a multiple of 8.
|
||||
static constexpr size_t kBlockHeaderSize = SerialArena::kBlockHeaderSize;
|
||||
static constexpr size_t kSerialArenaSize =
|
||||
(sizeof(SerialArena) + 7) & static_cast<size_t>(-8);
|
||||
static constexpr size_t kAllocPolicySize =
|
||||
AlignUpTo8(sizeof(AllocationPolicy));
|
||||
static constexpr size_t kMaxCleanupNodeSize = 16;
|
||||
static_assert(kBlockHeaderSize % 8 == 0,
|
||||
"kBlockHeaderSize must be a multiple of 8.");
|
||||
static_assert(kSerialArenaSize % 8 == 0,
|
||||
"kSerialArenaSize must be a multiple of 8.");
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ARENA_IMPL_H__
|
||||
51
libs/protobuf/src/google/protobuf/arena_test_util.cc
Normal file
51
libs/protobuf/src/google/protobuf/arena_test_util.cc
Normal file
@@ -0,0 +1,51 @@
|
||||
// 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/arena_test_util.h"
|
||||
|
||||
#include "google/protobuf/stubs/logging.h"
|
||||
#include "google/protobuf/stubs/common.h"
|
||||
|
||||
|
||||
#define EXPECT_EQ GOOGLE_CHECK_EQ
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
NoHeapChecker::~NoHeapChecker() {
|
||||
capture_alloc.Unhook();
|
||||
EXPECT_EQ(0, capture_alloc.alloc_count());
|
||||
EXPECT_EQ(0, capture_alloc.free_count());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
132
libs/protobuf/src/google/protobuf/arena_test_util.h
Normal file
132
libs/protobuf/src/google/protobuf/arena_test_util.h
Normal file
@@ -0,0 +1,132 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
|
||||
#define GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
|
||||
|
||||
#include "google/protobuf/stubs/logging.h"
|
||||
#include "google/protobuf/stubs/common.h"
|
||||
#include "google/protobuf/arena.h"
|
||||
#include "google/protobuf/io/coded_stream.h"
|
||||
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
template <typename T, bool use_arena>
|
||||
void TestParseCorruptedString(const T& message) {
|
||||
int success_count = 0;
|
||||
std::string s;
|
||||
{
|
||||
// Map order is not deterministic. To make the test deterministic we want
|
||||
// to serialize the proto deterministically.
|
||||
io::StringOutputStream output(&s);
|
||||
io::CodedOutputStream out(&output);
|
||||
out.SetSerializationDeterministic(true);
|
||||
message.SerializePartialToCodedStream(&out);
|
||||
}
|
||||
const int kMaxIters = 900;
|
||||
const int stride = s.size() <= kMaxIters ? 1 : s.size() / kMaxIters;
|
||||
const int start = stride == 1 || use_arena ? 0 : (stride + 1) / 2;
|
||||
for (int i = start; i < s.size(); i += stride) {
|
||||
for (int c = 1 + (i % 17); c < 256; c += 2 * c + (i & 3)) {
|
||||
s[i] ^= c;
|
||||
Arena arena;
|
||||
T* message = Arena::CreateMessage<T>(use_arena ? &arena : nullptr);
|
||||
if (message->ParseFromString(s)) {
|
||||
++success_count;
|
||||
}
|
||||
if (!use_arena) {
|
||||
delete message;
|
||||
}
|
||||
s[i] ^= c; // Restore s to its original state.
|
||||
}
|
||||
}
|
||||
// This next line is a low bar. But getting through the test without crashing
|
||||
// due to use-after-free or other bugs is a big part of what we're checking.
|
||||
GOOGLE_CHECK_GT(success_count, 0);
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
struct ArenaTestPeer {
|
||||
static void ReturnArrayMemory(Arena* arena, void* p, size_t size) {
|
||||
arena->ReturnArrayMemory(p, size);
|
||||
}
|
||||
};
|
||||
|
||||
class NoHeapChecker {
|
||||
public:
|
||||
NoHeapChecker() { capture_alloc.Hook(); }
|
||||
~NoHeapChecker();
|
||||
|
||||
private:
|
||||
class NewDeleteCapture {
|
||||
public:
|
||||
// TODO(xiaofeng): Implement this for opensource protobuf.
|
||||
void Hook() {}
|
||||
void Unhook() {}
|
||||
int alloc_count() { return 0; }
|
||||
int free_count() { return 0; }
|
||||
} capture_alloc;
|
||||
};
|
||||
|
||||
// Owns the internal T only if it's not owned by an arena.
|
||||
// T needs to be arena constructible and destructor skippable.
|
||||
template <typename T>
|
||||
class ArenaHolder {
|
||||
public:
|
||||
explicit ArenaHolder(Arena* arena)
|
||||
: field_(Arena::CreateMessage<T>(arena)),
|
||||
owned_by_arena_(arena != nullptr) {
|
||||
GOOGLE_DCHECK(google::protobuf::Arena::is_arena_constructable<T>::value);
|
||||
GOOGLE_DCHECK(google::protobuf::Arena::is_destructor_skippable<T>::value);
|
||||
}
|
||||
|
||||
~ArenaHolder() {
|
||||
if (!owned_by_arena_) {
|
||||
delete field_;
|
||||
}
|
||||
}
|
||||
|
||||
T* get() { return field_; }
|
||||
T* operator->() { return field_; }
|
||||
T& operator*() { return *field_; }
|
||||
|
||||
private:
|
||||
T* field_;
|
||||
bool owned_by_arena_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
|
||||
1605
libs/protobuf/src/google/protobuf/arena_unittest.cc
Normal file
1605
libs/protobuf/src/google/protobuf/arena_unittest.cc
Normal file
File diff suppressed because it is too large
Load Diff
279
libs/protobuf/src/google/protobuf/arenastring.cc
Normal file
279
libs/protobuf/src/google/protobuf/arenastring.cc
Normal file
@@ -0,0 +1,279 @@
|
||||
// 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/arenastring.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "google/protobuf/stubs/logging.h"
|
||||
#include "google/protobuf/stubs/common.h"
|
||||
#include "google/protobuf/io/coded_stream.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "google/protobuf/message_lite.h"
|
||||
#include "google/protobuf/parse_context.h"
|
||||
|
||||
// clang-format off
|
||||
#include "google/protobuf/port_def.inc"
|
||||
// clang-format on
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
|
||||
// TaggedStringPtr::Flags uses the lower 2 bits as tags.
|
||||
// Enforce that allocated data aligns to at least 4 bytes, and that
|
||||
// the alignment of the global const string value does as well.
|
||||
// The alignment guaranteed by `new std::string` depends on both:
|
||||
// - new align = __STDCPP_DEFAULT_NEW_ALIGNMENT__ / max_align_t
|
||||
// - alignof(std::string)
|
||||
#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
|
||||
constexpr size_t kNewAlign = __STDCPP_DEFAULT_NEW_ALIGNMENT__;
|
||||
#elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900
|
||||
constexpr size_t kNewAlign = alignof(::max_align_t);
|
||||
#else
|
||||
constexpr size_t kNewAlign = alignof(std::max_align_t);
|
||||
#endif
|
||||
constexpr size_t kStringAlign = alignof(std::string);
|
||||
|
||||
static_assert((kStringAlign > kNewAlign ? kStringAlign : kNewAlign) >= 4, "");
|
||||
static_assert(alignof(ExplicitlyConstructedArenaString) >= 4, "");
|
||||
|
||||
} // namespace
|
||||
|
||||
const std::string& LazyString::Init() const {
|
||||
static absl::Mutex mu{absl::kConstInit};
|
||||
mu.Lock();
|
||||
const std::string* res = inited_.load(std::memory_order_acquire);
|
||||
if (res == nullptr) {
|
||||
auto init_value = init_value_;
|
||||
res = ::new (static_cast<void*>(string_buf_))
|
||||
std::string(init_value.ptr, init_value.size);
|
||||
inited_.store(res, std::memory_order_release);
|
||||
}
|
||||
mu.Unlock();
|
||||
return *res;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
#if defined(NDEBUG) || !defined(GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL)
|
||||
|
||||
class ScopedCheckPtrInvariants {
|
||||
public:
|
||||
explicit ScopedCheckPtrInvariants(const TaggedStringPtr*) {}
|
||||
};
|
||||
|
||||
#endif // NDEBUG || !GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL
|
||||
|
||||
// Creates a heap allocated std::string value.
|
||||
inline TaggedStringPtr CreateString(absl::string_view value) {
|
||||
TaggedStringPtr res;
|
||||
res.SetAllocated(new std::string(value.data(), value.length()));
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL
|
||||
|
||||
// Creates an arena allocated std::string value.
|
||||
TaggedStringPtr CreateArenaString(Arena& arena, absl::string_view s) {
|
||||
TaggedStringPtr res;
|
||||
res.SetMutableArena(Arena::Create<std::string>(&arena, s.data(), s.length()));
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif // !GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL
|
||||
|
||||
} // namespace
|
||||
|
||||
void ArenaStringPtr::Set(absl::string_view value, Arena* arena) {
|
||||
ScopedCheckPtrInvariants check(&tagged_ptr_);
|
||||
if (IsDefault()) {
|
||||
// If we're not on an arena, skip straight to a true string to avoid
|
||||
// possible copy cost later.
|
||||
tagged_ptr_ = arena != nullptr ? CreateArenaString(*arena, value)
|
||||
: CreateString(value);
|
||||
} else {
|
||||
#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
|
||||
if (arena == nullptr) {
|
||||
auto* old = tagged_ptr_.GetIfAllocated();
|
||||
tagged_ptr_ = CreateString(value);
|
||||
delete old;
|
||||
} else {
|
||||
auto* old = UnsafeMutablePointer();
|
||||
tagged_ptr_ = CreateArenaString(*arena, value);
|
||||
old->assign("garbagedata");
|
||||
}
|
||||
#else // PROTOBUF_FORCE_COPY_DEFAULT_STRING
|
||||
UnsafeMutablePointer()->assign(value.data(), value.length());
|
||||
#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
|
||||
}
|
||||
}
|
||||
|
||||
void ArenaStringPtr::Set(std::string&& value, Arena* arena) {
|
||||
ScopedCheckPtrInvariants check(&tagged_ptr_);
|
||||
if (IsDefault()) {
|
||||
NewString(arena, std::move(value));
|
||||
} else if (IsFixedSizeArena()) {
|
||||
std::string* current = tagged_ptr_.Get();
|
||||
auto* s = new (current) std::string(std::move(value));
|
||||
arena->OwnDestructor(s);
|
||||
tagged_ptr_.SetMutableArena(s);
|
||||
} else /* !IsFixedSizeArena() */ {
|
||||
*UnsafeMutablePointer() = std::move(value);
|
||||
}
|
||||
}
|
||||
|
||||
std::string* ArenaStringPtr::Mutable(Arena* arena) {
|
||||
ScopedCheckPtrInvariants check(&tagged_ptr_);
|
||||
if (tagged_ptr_.IsMutable()) {
|
||||
return tagged_ptr_.Get();
|
||||
} else {
|
||||
return MutableSlow(arena);
|
||||
}
|
||||
}
|
||||
|
||||
std::string* ArenaStringPtr::Mutable(const LazyString& default_value,
|
||||
Arena* arena) {
|
||||
ScopedCheckPtrInvariants check(&tagged_ptr_);
|
||||
if (tagged_ptr_.IsMutable()) {
|
||||
return tagged_ptr_.Get();
|
||||
} else {
|
||||
return MutableSlow(arena, default_value);
|
||||
}
|
||||
}
|
||||
|
||||
std::string* ArenaStringPtr::MutableNoCopy(Arena* arena) {
|
||||
ScopedCheckPtrInvariants check(&tagged_ptr_);
|
||||
if (tagged_ptr_.IsMutable()) {
|
||||
return tagged_ptr_.Get();
|
||||
} else {
|
||||
GOOGLE_DCHECK(IsDefault());
|
||||
// Allocate empty. The contents are not relevant.
|
||||
return NewString(arena);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Lazy>
|
||||
std::string* ArenaStringPtr::MutableSlow(::google::protobuf::Arena* arena,
|
||||
const Lazy&... lazy_default) {
|
||||
GOOGLE_DCHECK(IsDefault());
|
||||
|
||||
// For empty defaults, this ends up calling the default constructor which is
|
||||
// more efficient than a copy construction from
|
||||
// GetEmptyStringAlreadyInited().
|
||||
return NewString(arena, lazy_default.get()...);
|
||||
}
|
||||
|
||||
std::string* ArenaStringPtr::Release() {
|
||||
ScopedCheckPtrInvariants check(&tagged_ptr_);
|
||||
if (IsDefault()) return nullptr;
|
||||
|
||||
std::string* released = tagged_ptr_.Get();
|
||||
if (tagged_ptr_.IsArena()) {
|
||||
released = tagged_ptr_.IsMutable() ? new std::string(std::move(*released))
|
||||
: new std::string(*released);
|
||||
}
|
||||
InitDefault();
|
||||
return released;
|
||||
}
|
||||
|
||||
void ArenaStringPtr::SetAllocated(std::string* value, Arena* arena) {
|
||||
ScopedCheckPtrInvariants check(&tagged_ptr_);
|
||||
// Release what we have first.
|
||||
Destroy();
|
||||
|
||||
if (value == nullptr) {
|
||||
InitDefault();
|
||||
} else {
|
||||
#ifndef NDEBUG
|
||||
// On debug builds, copy the string so the address differs. delete will
|
||||
// fail if value was a stack-allocated temporary/etc., which would have
|
||||
// failed when arena ran its cleanup list.
|
||||
std::string* new_value = new std::string(std::move(*value));
|
||||
delete value;
|
||||
value = new_value;
|
||||
#endif // !NDEBUG
|
||||
InitAllocated(value, arena);
|
||||
}
|
||||
}
|
||||
|
||||
void ArenaStringPtr::Destroy() {
|
||||
delete tagged_ptr_.GetIfAllocated();
|
||||
}
|
||||
|
||||
void ArenaStringPtr::ClearToEmpty() {
|
||||
ScopedCheckPtrInvariants check(&tagged_ptr_);
|
||||
if (IsDefault()) {
|
||||
// Already set to default -- do nothing.
|
||||
} else {
|
||||
// Unconditionally mask away the tag.
|
||||
//
|
||||
// UpdateArenaString uses assign when capacity is larger than the new
|
||||
// value, which is trivially true in the donated string case.
|
||||
// const_cast<std::string*>(PtrValue<std::string>())->clear();
|
||||
tagged_ptr_.Get()->clear();
|
||||
}
|
||||
}
|
||||
|
||||
void ArenaStringPtr::ClearToDefault(const LazyString& default_value,
|
||||
::google::protobuf::Arena* arena) {
|
||||
ScopedCheckPtrInvariants check(&tagged_ptr_);
|
||||
(void)arena;
|
||||
if (IsDefault()) {
|
||||
// Already set to default -- do nothing.
|
||||
} else {
|
||||
UnsafeMutablePointer()->assign(default_value.get());
|
||||
}
|
||||
}
|
||||
|
||||
const char* EpsCopyInputStream::ReadArenaString(const char* ptr,
|
||||
ArenaStringPtr* s,
|
||||
Arena* arena) {
|
||||
ScopedCheckPtrInvariants check(&s->tagged_ptr_);
|
||||
GOOGLE_DCHECK(arena != nullptr);
|
||||
|
||||
int size = ReadSize(&ptr);
|
||||
if (!ptr) return nullptr;
|
||||
|
||||
auto* str = s->NewString(arena);
|
||||
ptr = ReadString(ptr, size, str);
|
||||
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
481
libs/protobuf/src/google/protobuf/arenastring.h
Normal file
481
libs/protobuf/src/google/protobuf/arenastring.h
Normal file
@@ -0,0 +1,481 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ARENASTRING_H__
|
||||
#define GOOGLE_PROTOBUF_ARENASTRING_H__
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "google/protobuf/stubs/logging.h"
|
||||
#include "google/protobuf/stubs/common.h"
|
||||
#include "google/protobuf/arena.h"
|
||||
#include "google/protobuf/port.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "google/protobuf/explicitly_constructed.h"
|
||||
|
||||
// must be last:
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
#ifdef SWIG
|
||||
#error "You cannot SWIG proto headers"
|
||||
#endif
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
class EpsCopyInputStream;
|
||||
|
||||
class SwapFieldHelper;
|
||||
|
||||
// Declared in message_lite.h
|
||||
PROTOBUF_EXPORT extern ExplicitlyConstructedArenaString
|
||||
fixed_address_empty_string;
|
||||
|
||||
// Lazy string instance to support string fields with non-empty default.
|
||||
// These are initialized on the first call to .get().
|
||||
class PROTOBUF_EXPORT LazyString {
|
||||
public:
|
||||
// We explicitly make LazyString an aggregate so that MSVC can do constant
|
||||
// initialization on it without marking it `constexpr`.
|
||||
// We do not want to use `constexpr` because it makes it harder to have extern
|
||||
// storage for it and causes library bloat.
|
||||
struct InitValue {
|
||||
const char* ptr;
|
||||
size_t size;
|
||||
};
|
||||
// We keep a union of the initialization value and the std::string to save on
|
||||
// space. We don't need the string array after Init() is done.
|
||||
union {
|
||||
mutable InitValue init_value_;
|
||||
alignas(std::string) mutable char string_buf_[sizeof(std::string)];
|
||||
};
|
||||
mutable std::atomic<const std::string*> inited_;
|
||||
|
||||
const std::string& get() const {
|
||||
// This check generates less code than a call-once invocation.
|
||||
auto* res = inited_.load(std::memory_order_acquire);
|
||||
if (PROTOBUF_PREDICT_FALSE(res == nullptr)) return Init();
|
||||
return *res;
|
||||
}
|
||||
|
||||
private:
|
||||
// Initialize the string in `string_buf_`, update `inited_` and return it.
|
||||
// We return it here to avoid having to read it again in the inlined code.
|
||||
const std::string& Init() const;
|
||||
};
|
||||
|
||||
class TaggedStringPtr {
|
||||
public:
|
||||
// Bit flags qualifying string properties. We can use 2 bits as
|
||||
// ptr_ is guaranteed and enforced to be aligned on 4 byte boundaries.
|
||||
enum Flags {
|
||||
kArenaBit = 0x1, // ptr is arena allocated
|
||||
kMutableBit = 0x2, // ptr contents are fully mutable
|
||||
kMask = 0x3 // Bit mask
|
||||
};
|
||||
|
||||
// Composed logical types
|
||||
enum Type {
|
||||
// Default strings are immutable and never owned.
|
||||
kDefault = 0,
|
||||
|
||||
// Allocated strings are mutable and (as the name implies) owned.
|
||||
// A heap allocated string must be deleted.
|
||||
kAllocated = kMutableBit,
|
||||
|
||||
// Mutable arena strings are strings where the string instance is owned
|
||||
// by the arena, but the string contents itself are owned by the string
|
||||
// instance. Mutable arena string instances need to be destroyed which is
|
||||
// typically done through a cleanup action added to the arena owning it.
|
||||
kMutableArena = kArenaBit | kMutableBit,
|
||||
|
||||
// Fixed size arena strings are strings where both the string instance and
|
||||
// the string contents are fully owned by the arena. Fixed size arena
|
||||
// strings are a platform and c++ library specific customization. Fixed
|
||||
// size arena strings are immutable, with the exception of custom internal
|
||||
// updates to the content that fit inside the existing capacity.
|
||||
// Fixed size arena strings must never be deleted or destroyed.
|
||||
kFixedSizeArena = kArenaBit,
|
||||
};
|
||||
|
||||
TaggedStringPtr() = default;
|
||||
explicit constexpr TaggedStringPtr(ExplicitlyConstructedArenaString* ptr)
|
||||
: ptr_(ptr) {}
|
||||
|
||||
// Sets the value to `p`, tagging the value as being a 'default' value.
|
||||
// See documentation for kDefault for more info.
|
||||
inline const std::string* SetDefault(const std::string* p) {
|
||||
return TagAs(kDefault, const_cast<std::string*>(p));
|
||||
}
|
||||
|
||||
// Sets the value to `p`, tagging the value as a heap allocated value.
|
||||
// Allocated strings are mutable and (as the name implies) owned.
|
||||
// `p` must not be null
|
||||
inline std::string* SetAllocated(std::string* p) {
|
||||
return TagAs(kAllocated, p);
|
||||
}
|
||||
|
||||
// Sets the value to `p`, tagging the value as a fixed size arena string.
|
||||
// See documentation for kFixedSizeArena for more info.
|
||||
// `p` must not be null
|
||||
inline std::string* SetFixedSizeArena(std::string* p) {
|
||||
return TagAs(kFixedSizeArena, p);
|
||||
}
|
||||
|
||||
// Sets the value to `p`, tagging the value as a mutable arena string.
|
||||
// See documentation for kMutableArena for more info.
|
||||
// `p` must not be null
|
||||
inline std::string* SetMutableArena(std::string* p) {
|
||||
return TagAs(kMutableArena, p);
|
||||
}
|
||||
|
||||
// Returns true if the contents of the current string are fully mutable.
|
||||
inline bool IsMutable() const { return as_int() & kMutableBit; }
|
||||
|
||||
// Returns true if the current string is an immutable default value.
|
||||
inline bool IsDefault() const { return (as_int() & kMask) == kDefault; }
|
||||
|
||||
// If the current string is a heap-allocated mutable value, returns a pointer
|
||||
// to it. Returns nullptr otherwise.
|
||||
inline std::string *GetIfAllocated() const {
|
||||
auto allocated = as_int() ^ kAllocated;
|
||||
if (allocated & kMask) return nullptr;
|
||||
|
||||
auto ptr = reinterpret_cast<std::string*>(allocated);
|
||||
PROTOBUF_ASSUME(ptr != nullptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// Returns true if the current string is an arena allocated value.
|
||||
// This means it's either a mutable or fixed size arena string.
|
||||
inline bool IsArena() const { return as_int() & kArenaBit; }
|
||||
|
||||
// Returns true if the current string is a fixed size arena allocated value.
|
||||
inline bool IsFixedSizeArena() const {
|
||||
return (as_int() & kMask) == kFixedSizeArena;
|
||||
}
|
||||
|
||||
// Returns the contained string pointer.
|
||||
inline std::string* Get() const {
|
||||
return reinterpret_cast<std::string*>(as_int() & ~kMask);
|
||||
}
|
||||
|
||||
// Returns true if the contained pointer is null, indicating some error.
|
||||
// The Null value is only used during parsing for temporary values.
|
||||
// A persisted ArenaStringPtr value is never null.
|
||||
inline bool IsNull() { return ptr_ == nullptr; }
|
||||
|
||||
private:
|
||||
static inline void assert_aligned(const void* p) {
|
||||
GOOGLE_DCHECK_EQ(reinterpret_cast<uintptr_t>(p) & kMask, 0UL);
|
||||
}
|
||||
|
||||
inline std::string* TagAs(Type type, std::string* p) {
|
||||
GOOGLE_DCHECK(p != nullptr);
|
||||
assert_aligned(p);
|
||||
ptr_ = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(p) | type);
|
||||
return p;
|
||||
}
|
||||
|
||||
uintptr_t as_int() const { return reinterpret_cast<uintptr_t>(ptr_); }
|
||||
void* ptr_;
|
||||
};
|
||||
|
||||
static_assert(std::is_trivial<TaggedStringPtr>::value,
|
||||
"TaggedStringPtr must be trivial");
|
||||
|
||||
// This class encapsulates a pointer to a std::string with or without arena
|
||||
// owned contents, tagged by the bottom bits of the string pointer. It is a
|
||||
// high-level wrapper that almost directly corresponds to the interface required
|
||||
// by string fields in generated code. It replaces the old std::string* pointer
|
||||
// in such cases.
|
||||
//
|
||||
// The string pointer is tagged to be either a default, externally owned value,
|
||||
// a mutable heap allocated value, or an arena allocated value. The object uses
|
||||
// a single global instance of an empty string that is used as the initial
|
||||
// default value. Fields that have empty default values directly use this global
|
||||
// default. Fields that have non empty default values are supported through
|
||||
// lazily initialized default values managed by the LazyString class.
|
||||
//
|
||||
// Generated code and reflection code both ensure that ptr_ is never null.
|
||||
// Because ArenaStringPtr is used in oneof unions, its constructor is a NOP and
|
||||
// the field is always manually initialized via method calls.
|
||||
//
|
||||
// See TaggedStringPtr for more information about the types of string values
|
||||
// being held, and the mutable and ownership invariants for each type.
|
||||
struct PROTOBUF_EXPORT ArenaStringPtr {
|
||||
ArenaStringPtr() = default;
|
||||
constexpr ArenaStringPtr(ExplicitlyConstructedArenaString* default_value,
|
||||
ConstantInitialized)
|
||||
: tagged_ptr_(default_value) {}
|
||||
|
||||
// Called from generated code / reflection runtime only. Resets value to point
|
||||
// to a default string pointer, with the semantics that this ArenaStringPtr
|
||||
// does not own the pointed-to memory. Disregards initial value of ptr_ (so
|
||||
// this is the *ONLY* safe method to call after construction or when
|
||||
// reinitializing after becoming the active field in a oneof union).
|
||||
inline void InitDefault();
|
||||
|
||||
// Similar to `InitDefault` except that it allows the default value to be
|
||||
// initialized to an externally owned string. This method is called from
|
||||
// parsing code. `str` must not be null and outlive this instance.
|
||||
inline void InitExternal(const std::string* str);
|
||||
|
||||
// Called from generated code / reflection runtime only. Resets the value of
|
||||
// this instances to the heap allocated value in `str`. `str` must not be
|
||||
// null. Invokes `arena->Own(str)` to transfer ownership into the arena if
|
||||
// `arena` is not null, else, `str` will be owned by ArenaStringPtr. This
|
||||
// function should only be used to initialize a ArenaStringPtr or on an
|
||||
// instance known to not carry any heap allocated value.
|
||||
inline void InitAllocated(std::string* str, Arena* arena);
|
||||
|
||||
void Set(absl::string_view value, Arena* arena);
|
||||
void Set(std::string&& value, Arena* arena);
|
||||
void Set(const char* s, Arena* arena);
|
||||
void Set(const char* s, size_t n, Arena* arena);
|
||||
|
||||
void SetBytes(absl::string_view value, Arena* arena);
|
||||
void SetBytes(std::string&& value, Arena* arena);
|
||||
void SetBytes(const char* s, Arena* arena);
|
||||
void SetBytes(const void* p, size_t n, Arena* arena);
|
||||
|
||||
template <typename RefWrappedType>
|
||||
void Set(std::reference_wrapper<RefWrappedType> const_string_ref,
|
||||
::google::protobuf::Arena* arena) {
|
||||
Set(const_string_ref.get(), arena);
|
||||
}
|
||||
|
||||
// Returns a mutable std::string reference.
|
||||
// The version accepting a `LazyString` value is used in the generated code to
|
||||
// initialize mutable copies for fields with a non-empty default where the
|
||||
// default value is lazily initialized.
|
||||
std::string* Mutable(Arena* arena);
|
||||
std::string* Mutable(const LazyString& default_value, Arena* arena);
|
||||
|
||||
// Gets a mutable pointer with unspecified contents.
|
||||
// This function is identical to Mutable(), except it is optimized for the
|
||||
// case where the caller is not interested in the current contents. For
|
||||
// example, if the current field is not mutable, it will re-initialize the
|
||||
// value with an empty string rather than a (non-empty) default value.
|
||||
// Likewise, if the current value is a fixed size arena string with contents,
|
||||
// it will be initialized into an empty mutable arena string.
|
||||
std::string* MutableNoCopy(Arena* arena);
|
||||
|
||||
// Basic accessors.
|
||||
PROTOBUF_NDEBUG_INLINE const std::string& Get() const {
|
||||
// Unconditionally mask away the tag.
|
||||
return *tagged_ptr_.Get();
|
||||
}
|
||||
|
||||
// Returns a pointer to the stored contents for this instance.
|
||||
// This method is for internal debugging and tracking purposes only.
|
||||
PROTOBUF_NDEBUG_INLINE const std::string* UnsafeGetPointer() const
|
||||
PROTOBUF_RETURNS_NONNULL {
|
||||
return tagged_ptr_.Get();
|
||||
}
|
||||
|
||||
// Release returns a std::string* instance that is heap-allocated and is not
|
||||
// Own()'d by any arena. If the field is not set, this returns nullptr. The
|
||||
// caller retains ownership. Clears this field back to the default state.
|
||||
// Used to implement release_<field>() methods on generated classes.
|
||||
PROTOBUF_NODISCARD std::string* Release();
|
||||
|
||||
// Takes a std::string that is heap-allocated, and takes ownership. The
|
||||
// std::string's destructor is registered with the arena. Used to implement
|
||||
// set_allocated_<field> in generated classes.
|
||||
void SetAllocated(std::string* value, Arena* arena);
|
||||
|
||||
// Frees storage (if not on an arena).
|
||||
void Destroy();
|
||||
|
||||
// Clears content, but keeps allocated std::string, to avoid the overhead of
|
||||
// heap operations. After this returns, the content (as seen by the user) will
|
||||
// always be the empty std::string. Assumes that |default_value| is an empty
|
||||
// std::string.
|
||||
void ClearToEmpty();
|
||||
|
||||
// Clears content, assuming that the current value is not the empty
|
||||
// string default.
|
||||
void ClearNonDefaultToEmpty();
|
||||
|
||||
// Clears content, but keeps allocated std::string if arena != nullptr, to
|
||||
// avoid the overhead of heap operations. After this returns, the content
|
||||
// (as seen by the user) will always be equal to |default_value|.
|
||||
void ClearToDefault(const LazyString& default_value, ::google::protobuf::Arena* arena);
|
||||
|
||||
// Swaps internal pointers. Arena-safety semantics: this is guarded by the
|
||||
// logic in Swap()/UnsafeArenaSwap() at the message level, so this method is
|
||||
// 'unsafe' if called directly.
|
||||
inline PROTOBUF_NDEBUG_INLINE static void InternalSwap(ArenaStringPtr* rhs,
|
||||
Arena* rhs_arena,
|
||||
ArenaStringPtr* lhs,
|
||||
Arena* lhs_arena);
|
||||
|
||||
// Internal setter used only at parse time to directly set a donated string
|
||||
// value.
|
||||
void UnsafeSetTaggedPointer(TaggedStringPtr value) { tagged_ptr_ = value; }
|
||||
// Generated code only! An optimization, in certain cases the generated
|
||||
// code is certain we can obtain a std::string with no default checks and
|
||||
// tag tests.
|
||||
std::string* UnsafeMutablePointer() PROTOBUF_RETURNS_NONNULL;
|
||||
|
||||
// Returns true if this instances holds an immutable default value.
|
||||
inline bool IsDefault() const { return tagged_ptr_.IsDefault(); }
|
||||
|
||||
private:
|
||||
template <typename... Args>
|
||||
inline std::string* NewString(Arena* arena, Args&&... args) {
|
||||
if (arena == nullptr) {
|
||||
auto* s = new std::string(std::forward<Args>(args)...);
|
||||
return tagged_ptr_.SetAllocated(s);
|
||||
} else {
|
||||
auto* s = Arena::Create<std::string>(arena, std::forward<Args>(args)...);
|
||||
return tagged_ptr_.SetMutableArena(s);
|
||||
}
|
||||
}
|
||||
|
||||
TaggedStringPtr tagged_ptr_;
|
||||
|
||||
bool IsFixedSizeArena() const { return false; }
|
||||
|
||||
// Swaps tagged pointer without debug hardening. This is to allow python
|
||||
// protobuf to maintain pointer stability even in DEBUG builds.
|
||||
inline PROTOBUF_NDEBUG_INLINE static void UnsafeShallowSwap(
|
||||
ArenaStringPtr* rhs, ArenaStringPtr* lhs) {
|
||||
std::swap(lhs->tagged_ptr_, rhs->tagged_ptr_);
|
||||
}
|
||||
|
||||
friend class ::google::protobuf::internal::SwapFieldHelper;
|
||||
friend class TcParser;
|
||||
|
||||
// Slow paths.
|
||||
|
||||
// MutableSlow requires that !IsString() || IsDefault
|
||||
// Variadic to support 0 args for empty default and 1 arg for LazyString.
|
||||
template <typename... Lazy>
|
||||
std::string* MutableSlow(::google::protobuf::Arena* arena, const Lazy&... lazy_default);
|
||||
|
||||
friend class EpsCopyInputStream;
|
||||
};
|
||||
|
||||
inline void ArenaStringPtr::InitDefault() {
|
||||
tagged_ptr_ = TaggedStringPtr(&fixed_address_empty_string);
|
||||
}
|
||||
|
||||
inline void ArenaStringPtr::InitExternal(const std::string* str) {
|
||||
tagged_ptr_.SetDefault(str);
|
||||
}
|
||||
|
||||
inline void ArenaStringPtr::InitAllocated(std::string* str, Arena* arena) {
|
||||
if (arena != nullptr) {
|
||||
tagged_ptr_.SetMutableArena(str);
|
||||
arena->Own(str);
|
||||
} else {
|
||||
tagged_ptr_.SetAllocated(str);
|
||||
}
|
||||
}
|
||||
|
||||
inline void ArenaStringPtr::Set(const char* s, Arena* arena) {
|
||||
Set(absl::string_view{s}, arena);
|
||||
}
|
||||
|
||||
inline void ArenaStringPtr::Set(const char* s, size_t n, Arena* arena) {
|
||||
Set(absl::string_view{s, n}, arena);
|
||||
}
|
||||
|
||||
inline void ArenaStringPtr::SetBytes(absl::string_view value, Arena* arena) {
|
||||
Set(value, arena);
|
||||
}
|
||||
|
||||
inline void ArenaStringPtr::SetBytes(std::string&& value, Arena* arena) {
|
||||
Set(std::move(value), arena);
|
||||
}
|
||||
|
||||
inline void ArenaStringPtr::SetBytes(const char* s, Arena* arena) {
|
||||
Set(s, arena);
|
||||
}
|
||||
|
||||
inline void ArenaStringPtr::SetBytes(const void* p, size_t n, Arena* arena) {
|
||||
Set(absl::string_view{static_cast<const char*>(p), n}, arena);
|
||||
}
|
||||
|
||||
// Make sure rhs_arena allocated rhs, and lhs_arena allocated lhs.
|
||||
inline PROTOBUF_NDEBUG_INLINE void ArenaStringPtr::InternalSwap( //
|
||||
ArenaStringPtr* rhs, Arena* rhs_arena, //
|
||||
ArenaStringPtr* lhs, Arena* lhs_arena) {
|
||||
// Silence unused variable warnings in release buildls.
|
||||
(void)rhs_arena;
|
||||
(void)lhs_arena;
|
||||
std::swap(lhs->tagged_ptr_, rhs->tagged_ptr_);
|
||||
#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
|
||||
auto force_realloc = [](ArenaStringPtr* p, Arena* arena) {
|
||||
if (p->IsDefault()) return;
|
||||
std::string* old_value = p->tagged_ptr_.Get();
|
||||
std::string* new_value =
|
||||
p->IsFixedSizeArena()
|
||||
? Arena::Create<std::string>(arena, *old_value)
|
||||
: Arena::Create<std::string>(arena, std::move(*old_value));
|
||||
if (arena == nullptr) {
|
||||
delete old_value;
|
||||
p->tagged_ptr_.SetAllocated(new_value);
|
||||
} else {
|
||||
p->tagged_ptr_.SetMutableArena(new_value);
|
||||
}
|
||||
};
|
||||
// Because, at this point, tagged_ptr_ has been swapped, arena should also be
|
||||
// swapped.
|
||||
force_realloc(lhs, rhs_arena);
|
||||
force_realloc(rhs, lhs_arena);
|
||||
#endif // PROTOBUF_FORCE_COPY_IN_SWAP
|
||||
}
|
||||
|
||||
inline void ArenaStringPtr::ClearNonDefaultToEmpty() {
|
||||
// Unconditionally mask away the tag.
|
||||
tagged_ptr_.Get()->clear();
|
||||
}
|
||||
|
||||
inline std::string* ArenaStringPtr::UnsafeMutablePointer() {
|
||||
GOOGLE_DCHECK(tagged_ptr_.IsMutable());
|
||||
GOOGLE_DCHECK(tagged_ptr_.Get() != nullptr);
|
||||
return tagged_ptr_.Get();
|
||||
}
|
||||
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ARENASTRING_H__
|
||||
154
libs/protobuf/src/google/protobuf/arenastring_unittest.cc
Normal file
154
libs/protobuf/src/google/protobuf/arenastring_unittest.cc
Normal file
@@ -0,0 +1,154 @@
|
||||
// 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/arenastring.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "google/protobuf/stubs/logging.h"
|
||||
#include "google/protobuf/stubs/common.h"
|
||||
#include "google/protobuf/io/coded_stream.h"
|
||||
#include "google/protobuf/io/zero_copy_stream_impl.h"
|
||||
#include "google/protobuf/generated_message_util.h"
|
||||
#include "google/protobuf/message_lite.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
using internal::ArenaStringPtr;
|
||||
|
||||
const internal::LazyString nonempty_default{{{"default", 7}}, {nullptr}};
|
||||
const std::string* empty_default = &internal::GetEmptyString();
|
||||
|
||||
class SingleArena : public testing::TestWithParam<bool> {
|
||||
public:
|
||||
std::unique_ptr<Arena> GetArena() {
|
||||
if (this->GetParam()) return nullptr;
|
||||
return std::unique_ptr<Arena>(new Arena());
|
||||
}
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(ArenaString, SingleArena, testing::Bool());
|
||||
|
||||
TEST_P(SingleArena, GetSet) {
|
||||
auto arena = GetArena();
|
||||
ArenaStringPtr field;
|
||||
field.InitDefault();
|
||||
EXPECT_EQ("", field.Get());
|
||||
field.Set("Test short", arena.get());
|
||||
EXPECT_EQ("Test short", field.Get());
|
||||
field.Set("Test long long long long value", arena.get());
|
||||
EXPECT_EQ("Test long long long long value", field.Get());
|
||||
field.Set("", arena.get());
|
||||
field.Destroy();
|
||||
}
|
||||
|
||||
TEST_P(SingleArena, MutableAccessor) {
|
||||
auto arena = GetArena();
|
||||
ArenaStringPtr field;
|
||||
field.InitDefault();
|
||||
|
||||
std::string* mut = field.Mutable(arena.get());
|
||||
EXPECT_EQ(mut, field.Mutable(arena.get()));
|
||||
EXPECT_EQ(mut, &field.Get());
|
||||
EXPECT_NE(empty_default, mut);
|
||||
EXPECT_EQ("", *mut);
|
||||
*mut = "Test long long long long value"; // ensure string allocates storage
|
||||
EXPECT_EQ("Test long long long long value", field.Get());
|
||||
field.Destroy();
|
||||
}
|
||||
|
||||
TEST_P(SingleArena, NullDefault) {
|
||||
auto arena = GetArena();
|
||||
|
||||
ArenaStringPtr field;
|
||||
field.InitDefault();
|
||||
std::string* mut = field.Mutable(nonempty_default, arena.get());
|
||||
EXPECT_EQ(mut, field.Mutable(nonempty_default, arena.get()));
|
||||
EXPECT_EQ(mut, &field.Get());
|
||||
EXPECT_NE(nullptr, mut);
|
||||
EXPECT_EQ("default", *mut);
|
||||
*mut = "Test long long long long value"; // ensure string allocates storage
|
||||
EXPECT_EQ("Test long long long long value", field.Get());
|
||||
field.Destroy();
|
||||
}
|
||||
|
||||
class DualArena : public testing::TestWithParam<std::tuple<bool, bool>> {
|
||||
public:
|
||||
std::unique_ptr<Arena> GetLhsArena() {
|
||||
if (std::get<0>(this->GetParam())) return nullptr;
|
||||
return std::unique_ptr<Arena>(new Arena());
|
||||
}
|
||||
std::unique_ptr<Arena> GetRhsArena() {
|
||||
if (std::get<1>(this->GetParam())) return nullptr;
|
||||
return std::unique_ptr<Arena>(new Arena());
|
||||
}
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(ArenaString, DualArena,
|
||||
testing::Combine(testing::Bool(), testing::Bool()));
|
||||
|
||||
TEST_P(DualArena, Swap) {
|
||||
auto lhs_arena = GetLhsArena();
|
||||
ArenaStringPtr lhs;
|
||||
lhs.InitDefault();
|
||||
ArenaStringPtr rhs;
|
||||
rhs.InitDefault();
|
||||
|
||||
{
|
||||
auto rhs_arena = GetRhsArena();
|
||||
lhs.Set("lhs value that has some heft", lhs_arena.get());
|
||||
rhs.Set("rhs value that has some heft", rhs_arena.get());
|
||||
ArenaStringPtr::InternalSwap(&lhs, lhs_arena.get(), //
|
||||
&rhs, rhs_arena.get());
|
||||
EXPECT_EQ("rhs value that has some heft", lhs.Get());
|
||||
EXPECT_EQ("lhs value that has some heft", rhs.Get());
|
||||
lhs.Destroy();
|
||||
}
|
||||
EXPECT_EQ("lhs value that has some heft", rhs.Get());
|
||||
rhs.Destroy();
|
||||
}
|
||||
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
246
libs/protobuf/src/google/protobuf/arenaz_sampler.cc
Normal file
246
libs/protobuf/src/google/protobuf/arenaz_sampler.cc
Normal file
@@ -0,0 +1,246 @@
|
||||
// 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/arenaz_sampler.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
ThreadSafeArenazSampler& GlobalThreadSafeArenazSampler() {
|
||||
static auto* sampler = new ThreadSafeArenazSampler();
|
||||
return *sampler;
|
||||
}
|
||||
|
||||
void UnsampleSlow(ThreadSafeArenaStats* info) {
|
||||
GlobalThreadSafeArenazSampler().Unregister(info);
|
||||
}
|
||||
|
||||
#if defined(PROTOBUF_ARENAZ_SAMPLE)
|
||||
namespace {
|
||||
|
||||
PROTOBUF_CONSTINIT std::atomic<bool> g_arenaz_enabled{true};
|
||||
PROTOBUF_CONSTINIT std::atomic<int32_t> g_arenaz_sample_parameter{1 << 10};
|
||||
PROTOBUF_CONSTINIT std::atomic<ThreadSafeArenazConfigListener>
|
||||
g_arenaz_config_listener{nullptr};
|
||||
PROTOBUF_THREAD_LOCAL absl::profiling_internal::ExponentialBiased
|
||||
g_exponential_biased_generator;
|
||||
|
||||
void TriggerThreadSafeArenazConfigListener() {
|
||||
auto* listener = g_arenaz_config_listener.load(std::memory_order_acquire);
|
||||
if (listener != nullptr) listener();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PROTOBUF_THREAD_LOCAL SamplingState global_sampling_state = {
|
||||
/*next_sample=*/0, /*sample_stride=*/0};
|
||||
|
||||
ThreadSafeArenaStats::ThreadSafeArenaStats() { PrepareForSampling(0); }
|
||||
ThreadSafeArenaStats::~ThreadSafeArenaStats() = default;
|
||||
|
||||
void ThreadSafeArenaStats::BlockStats::PrepareForSampling() {
|
||||
num_allocations.store(0, std::memory_order_relaxed);
|
||||
bytes_allocated.store(0, std::memory_order_relaxed);
|
||||
bytes_used.store(0, std::memory_order_relaxed);
|
||||
bytes_wasted.store(0, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void ThreadSafeArenaStats::PrepareForSampling(int64_t stride) {
|
||||
for (auto& blockstats : block_histogram) blockstats.PrepareForSampling();
|
||||
max_block_size.store(0, std::memory_order_relaxed);
|
||||
thread_ids.store(0, std::memory_order_relaxed);
|
||||
weight = stride;
|
||||
// The inliner makes hardcoded skip_count difficult (especially when combined
|
||||
// with LTO). We use the ability to exclude stacks by regex when encoding
|
||||
// instead.
|
||||
depth = absl::GetStackTrace(stack, kMaxStackDepth, /* skip_count= */ 0);
|
||||
}
|
||||
|
||||
size_t ThreadSafeArenaStats::FindBin(size_t bytes) {
|
||||
if (bytes <= kMaxSizeForBinZero) return 0;
|
||||
if (bytes <= kMaxSizeForPenultimateBin) {
|
||||
// absl::bit_width() returns one plus the base-2 logarithm of x, with any
|
||||
// fractional part discarded.
|
||||
return absl::bit_width(absl::bit_ceil(bytes)) - kLogMaxSizeForBinZero - 1;
|
||||
}
|
||||
return kBlockHistogramBins - 1;
|
||||
}
|
||||
|
||||
std::pair<size_t, size_t> ThreadSafeArenaStats::MinMaxBlockSizeForBin(
|
||||
size_t bin) {
|
||||
ABSL_ASSERT(bin < kBlockHistogramBins);
|
||||
if (bin == 0) return {1, kMaxSizeForBinZero};
|
||||
if (bin < kBlockHistogramBins - 1) {
|
||||
return {(1 << (kLogMaxSizeForBinZero + bin - 1)) + 1,
|
||||
1 << (kLogMaxSizeForBinZero + bin)};
|
||||
}
|
||||
return {kMaxSizeForPenultimateBin + 1, std::numeric_limits<size_t>::max()};
|
||||
}
|
||||
|
||||
void RecordAllocateSlow(ThreadSafeArenaStats* info, size_t used,
|
||||
size_t allocated, size_t wasted) {
|
||||
// Update the allocated bytes for the current block.
|
||||
ThreadSafeArenaStats::BlockStats& curr =
|
||||
info->block_histogram[ThreadSafeArenaStats::FindBin(allocated)];
|
||||
curr.bytes_allocated.fetch_add(allocated, std::memory_order_relaxed);
|
||||
curr.num_allocations.fetch_add(1, std::memory_order_relaxed);
|
||||
|
||||
// Update the used and wasted bytes for the previous block.
|
||||
ThreadSafeArenaStats::BlockStats& prev =
|
||||
info->block_histogram[ThreadSafeArenaStats::FindBin(used + wasted)];
|
||||
prev.bytes_used.fetch_add(used, std::memory_order_relaxed);
|
||||
prev.bytes_wasted.fetch_add(wasted, std::memory_order_relaxed);
|
||||
|
||||
if (info->max_block_size.load(std::memory_order_relaxed) < allocated) {
|
||||
info->max_block_size.store(allocated, std::memory_order_relaxed);
|
||||
}
|
||||
const uint64_t tid = 1ULL << (GetCachedTID() % 63);
|
||||
info->thread_ids.fetch_or(tid, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
ThreadSafeArenaStats* SampleSlow(SamplingState& sampling_state) {
|
||||
bool first = sampling_state.next_sample < 0;
|
||||
const int64_t next_stride = g_exponential_biased_generator.GetStride(
|
||||
g_arenaz_sample_parameter.load(std::memory_order_relaxed));
|
||||
// Small values of interval are equivalent to just sampling next time.
|
||||
ABSL_ASSERT(next_stride >= 1);
|
||||
sampling_state.next_sample = next_stride;
|
||||
const int64_t old_stride =
|
||||
absl::exchange(sampling_state.sample_stride, next_stride);
|
||||
|
||||
// g_arenaz_enabled can be dynamically flipped, we need to set a threshold low
|
||||
// enough that we will start sampling in a reasonable time, so we just use the
|
||||
// default sampling rate.
|
||||
if (!g_arenaz_enabled.load(std::memory_order_relaxed)) return nullptr;
|
||||
// We will only be negative on our first count, so we should just retry in
|
||||
// that case.
|
||||
if (first) {
|
||||
if (PROTOBUF_PREDICT_TRUE(--sampling_state.next_sample > 0)) return nullptr;
|
||||
return SampleSlow(sampling_state);
|
||||
}
|
||||
|
||||
return GlobalThreadSafeArenazSampler().Register(old_stride);
|
||||
}
|
||||
|
||||
void SetThreadSafeArenazConfigListener(ThreadSafeArenazConfigListener l) {
|
||||
g_arenaz_config_listener.store(l, std::memory_order_release);
|
||||
}
|
||||
|
||||
bool IsThreadSafeArenazEnabled() {
|
||||
return g_arenaz_enabled.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
void SetThreadSafeArenazEnabled(bool enabled) {
|
||||
SetThreadSafeArenazEnabledInternal(enabled);
|
||||
TriggerThreadSafeArenazConfigListener();
|
||||
}
|
||||
|
||||
void SetThreadSafeArenazEnabledInternal(bool enabled) {
|
||||
g_arenaz_enabled.store(enabled, std::memory_order_release);
|
||||
}
|
||||
|
||||
void SetThreadSafeArenazSampleParameter(int32_t rate) {
|
||||
SetThreadSafeArenazSampleParameterInternal(rate);
|
||||
TriggerThreadSafeArenazConfigListener();
|
||||
}
|
||||
|
||||
void SetThreadSafeArenazSampleParameterInternal(int32_t rate) {
|
||||
if (rate > 0) {
|
||||
g_arenaz_sample_parameter.store(rate, std::memory_order_release);
|
||||
} else {
|
||||
ABSL_RAW_LOG(ERROR, "Invalid thread safe arenaz sample rate: %lld",
|
||||
static_cast<long long>(rate)); // NOLINT(runtime/int)
|
||||
}
|
||||
}
|
||||
|
||||
int32_t ThreadSafeArenazSampleParameter() {
|
||||
return g_arenaz_sample_parameter.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void SetThreadSafeArenazMaxSamples(int32_t max) {
|
||||
SetThreadSafeArenazMaxSamplesInternal(max);
|
||||
TriggerThreadSafeArenazConfigListener();
|
||||
}
|
||||
|
||||
void SetThreadSafeArenazMaxSamplesInternal(int32_t max) {
|
||||
if (max > 0) {
|
||||
GlobalThreadSafeArenazSampler().SetMaxSamples(max);
|
||||
} else {
|
||||
ABSL_RAW_LOG(ERROR, "Invalid thread safe arenaz max samples: %lld",
|
||||
static_cast<long long>(max)); // NOLINT(runtime/int)
|
||||
}
|
||||
}
|
||||
|
||||
size_t ThreadSafeArenazMaxSamples() {
|
||||
return GlobalThreadSafeArenazSampler().GetMaxSamples();
|
||||
}
|
||||
|
||||
void SetThreadSafeArenazGlobalNextSample(int64_t next_sample) {
|
||||
if (next_sample >= 0) {
|
||||
global_sampling_state.next_sample = next_sample;
|
||||
global_sampling_state.sample_stride = next_sample;
|
||||
} else {
|
||||
ABSL_RAW_LOG(ERROR, "Invalid thread safe arenaz next sample: %lld",
|
||||
static_cast<long long>(next_sample)); // NOLINT(runtime/int)
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
ThreadSafeArenaStats* SampleSlow(int64_t* next_sample) {
|
||||
*next_sample = std::numeric_limits<int64_t>::max();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SetThreadSafeArenazConfigListener(ThreadSafeArenazConfigListener) {}
|
||||
void SetThreadSafeArenazEnabled(bool enabled) {}
|
||||
void SetThreadSafeArenazEnabledInternal(bool enabled) {}
|
||||
bool IsThreadSafeArenazEnabled() { return false; }
|
||||
void SetThreadSafeArenazSampleParameter(int32_t rate) {}
|
||||
void SetThreadSafeArenazSampleParameterInternal(int32_t rate) {}
|
||||
int32_t ThreadSafeArenazSampleParameter() { return 0; }
|
||||
void SetThreadSafeArenazMaxSamples(int32_t max) {}
|
||||
void SetThreadSafeArenazMaxSamplesInternal(int32_t max) {}
|
||||
size_t ThreadSafeArenazMaxSamples() { return 0; }
|
||||
void SetThreadSafeArenazGlobalNextSample(int64_t next_sample) {}
|
||||
#endif // defined(PROTOBUF_ARENAZ_SAMPLE)
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
261
libs/protobuf/src/google/protobuf/arenaz_sampler.h
Normal file
261
libs/protobuf/src/google/protobuf/arenaz_sampler.h
Normal file
@@ -0,0 +1,261 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_SRC_GOOGLE_PROTOBUF_ARENAZ_SAMPLER_H__
|
||||
#define GOOGLE_PROTOBUF_SRC_GOOGLE_PROTOBUF_ARENAZ_SAMPLER_H__
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
#if defined(PROTOBUF_ARENAZ_SAMPLE)
|
||||
struct ThreadSafeArenaStats;
|
||||
void RecordAllocateSlow(ThreadSafeArenaStats* info, size_t used,
|
||||
size_t allocated, size_t wasted);
|
||||
// Stores information about a sampled thread safe arena. All mutations to this
|
||||
// *must* be made through `Record*` functions below. All reads from this *must*
|
||||
// only occur in the callback to `ThreadSafeArenazSampler::Iterate`.
|
||||
struct ThreadSafeArenaStats
|
||||
: public absl::profiling_internal::Sample<ThreadSafeArenaStats> {
|
||||
// Constructs the object but does not fill in any fields.
|
||||
ThreadSafeArenaStats();
|
||||
~ThreadSafeArenaStats();
|
||||
|
||||
// Puts the object into a clean state, fills in the logically `const` members,
|
||||
// blocking for any readers that are currently sampling the object. The
|
||||
// 'stride' parameter is the number of ThreadSafeArenas that were instantiated
|
||||
// between this sample and the previous one.
|
||||
void PrepareForSampling(int64_t stride)
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(init_mu);
|
||||
|
||||
// These fields are mutated by the various Record* APIs and need to be
|
||||
// thread-safe.
|
||||
struct BlockStats {
|
||||
std::atomic<int> num_allocations;
|
||||
std::atomic<size_t> bytes_allocated;
|
||||
std::atomic<size_t> bytes_used;
|
||||
std::atomic<size_t> bytes_wasted;
|
||||
|
||||
void PrepareForSampling();
|
||||
};
|
||||
|
||||
// block_histogram is a kBlockHistogramBins sized histogram. The zeroth bin
|
||||
// stores info about blocks of size \in [1, 1 << kLogMaxSizeForBinZero]. Bin
|
||||
// i, where i > 0, stores info for blocks of size \in (max_size_bin (i-1),
|
||||
// 1 << (kLogMaxSizeForBinZero + i)]. The final bin stores info about blocks
|
||||
// of size \in [kMaxSizeForPenultimateBin + 1,
|
||||
// std::numeric_limits<size_t>::max()].
|
||||
static constexpr size_t kBlockHistogramBins = 15;
|
||||
static constexpr size_t kLogMaxSizeForBinZero = 7;
|
||||
static constexpr size_t kMaxSizeForBinZero = (1 << kLogMaxSizeForBinZero);
|
||||
static constexpr size_t kMaxSizeForPenultimateBin =
|
||||
1 << (kLogMaxSizeForBinZero + kBlockHistogramBins - 2);
|
||||
std::array<BlockStats, kBlockHistogramBins> block_histogram;
|
||||
|
||||
// Records the largest block allocated for the arena.
|
||||
std::atomic<size_t> max_block_size;
|
||||
// Bit `i` is set to 1 indicates that a thread with `tid % 63 = i` accessed
|
||||
// the underlying arena. We use `% 63` as a rudimentary hash to ensure some
|
||||
// bit mixing for thread-ids; `% 64` would only grab the low bits and might
|
||||
// create sampling artifacts.
|
||||
std::atomic<uint64_t> thread_ids;
|
||||
|
||||
// All of the fields below are set by `PrepareForSampling`, they must not
|
||||
// be mutated in `Record*` functions. They are logically `const` in that
|
||||
// sense. These are guarded by init_mu, but that is not externalized to
|
||||
// clients, who can only read them during
|
||||
// `ThreadSafeArenazSampler::Iterate` which will hold the lock.
|
||||
static constexpr int kMaxStackDepth = 64;
|
||||
int32_t depth;
|
||||
void* stack[kMaxStackDepth];
|
||||
static void RecordAllocateStats(ThreadSafeArenaStats* info, size_t used,
|
||||
size_t allocated, size_t wasted) {
|
||||
if (PROTOBUF_PREDICT_TRUE(info == nullptr)) return;
|
||||
RecordAllocateSlow(info, used, allocated, wasted);
|
||||
}
|
||||
|
||||
// Returns the bin for the provided size.
|
||||
static size_t FindBin(size_t bytes);
|
||||
|
||||
// Returns the min and max bytes that can be stored in the histogram for
|
||||
// blocks in the provided bin.
|
||||
static std::pair<size_t, size_t> MinMaxBlockSizeForBin(size_t bin);
|
||||
};
|
||||
|
||||
struct SamplingState {
|
||||
// Number of ThreadSafeArenas that should be instantiated before the next
|
||||
// ThreadSafeArena is sampled. This variable is decremented with each
|
||||
// instantiation.
|
||||
int64_t next_sample;
|
||||
// When we make a sampling decision, we record that distance between from the
|
||||
// previous sample so we can weight each sample. 'distance' here is the
|
||||
// number of instantiations of ThreadSafeArena.
|
||||
int64_t sample_stride;
|
||||
};
|
||||
|
||||
ThreadSafeArenaStats* SampleSlow(SamplingState& sampling_state);
|
||||
void UnsampleSlow(ThreadSafeArenaStats* info);
|
||||
|
||||
class ThreadSafeArenaStatsHandle {
|
||||
public:
|
||||
explicit ThreadSafeArenaStatsHandle() = default;
|
||||
explicit ThreadSafeArenaStatsHandle(ThreadSafeArenaStats* info)
|
||||
: info_(info) {}
|
||||
|
||||
~ThreadSafeArenaStatsHandle() {
|
||||
if (PROTOBUF_PREDICT_TRUE(info_ == nullptr)) return;
|
||||
UnsampleSlow(info_);
|
||||
}
|
||||
|
||||
ThreadSafeArenaStatsHandle(ThreadSafeArenaStatsHandle&& other) noexcept
|
||||
: info_(absl::exchange(other.info_, nullptr)) {}
|
||||
|
||||
ThreadSafeArenaStatsHandle& operator=(
|
||||
ThreadSafeArenaStatsHandle&& other) noexcept {
|
||||
if (PROTOBUF_PREDICT_FALSE(info_ != nullptr)) {
|
||||
UnsampleSlow(info_);
|
||||
}
|
||||
info_ = absl::exchange(other.info_, nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ThreadSafeArenaStats* MutableStats() { return info_; }
|
||||
|
||||
friend void swap(ThreadSafeArenaStatsHandle& lhs,
|
||||
ThreadSafeArenaStatsHandle& rhs) {
|
||||
std::swap(lhs.info_, rhs.info_);
|
||||
}
|
||||
|
||||
friend class ThreadSafeArenaStatsHandlePeer;
|
||||
|
||||
private:
|
||||
ThreadSafeArenaStats* info_ = nullptr;
|
||||
};
|
||||
|
||||
using ThreadSafeArenazSampler =
|
||||
::absl::profiling_internal::SampleRecorder<ThreadSafeArenaStats>;
|
||||
|
||||
extern PROTOBUF_THREAD_LOCAL SamplingState global_sampling_state;
|
||||
|
||||
// Returns an RAII sampling handle that manages registration and unregistation
|
||||
// with the global sampler.
|
||||
inline ThreadSafeArenaStatsHandle Sample() {
|
||||
if (PROTOBUF_PREDICT_TRUE(--global_sampling_state.next_sample > 0)) {
|
||||
return ThreadSafeArenaStatsHandle(nullptr);
|
||||
}
|
||||
return ThreadSafeArenaStatsHandle(SampleSlow(global_sampling_state));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
using SamplingState = int64_t;
|
||||
|
||||
struct ThreadSafeArenaStats {
|
||||
static void RecordAllocateStats(ThreadSafeArenaStats*, size_t /*requested*/,
|
||||
size_t /*allocated*/, size_t /*wasted*/) {}
|
||||
};
|
||||
|
||||
ThreadSafeArenaStats* SampleSlow(SamplingState& next_sample);
|
||||
void UnsampleSlow(ThreadSafeArenaStats* info);
|
||||
|
||||
class ThreadSafeArenaStatsHandle {
|
||||
public:
|
||||
explicit ThreadSafeArenaStatsHandle() = default;
|
||||
explicit ThreadSafeArenaStatsHandle(ThreadSafeArenaStats*) {}
|
||||
|
||||
void RecordReset() {}
|
||||
|
||||
ThreadSafeArenaStats* MutableStats() { return nullptr; }
|
||||
|
||||
friend void swap(ThreadSafeArenaStatsHandle&, ThreadSafeArenaStatsHandle&) {}
|
||||
|
||||
private:
|
||||
friend class ThreadSafeArenaStatsHandlePeer;
|
||||
};
|
||||
|
||||
class ThreadSafeArenazSampler {
|
||||
public:
|
||||
void Unregister(ThreadSafeArenaStats*) {}
|
||||
void SetMaxSamples(int32_t) {}
|
||||
};
|
||||
|
||||
// Returns an RAII sampling handle that manages registration and unregistation
|
||||
// with the global sampler.
|
||||
inline ThreadSafeArenaStatsHandle Sample() {
|
||||
return ThreadSafeArenaStatsHandle(nullptr);
|
||||
}
|
||||
#endif // defined(PROTOBUF_ARENAZ_SAMPLE)
|
||||
|
||||
// Returns a global Sampler.
|
||||
ThreadSafeArenazSampler& GlobalThreadSafeArenazSampler();
|
||||
|
||||
using ThreadSafeArenazConfigListener = void (*)();
|
||||
void SetThreadSafeArenazConfigListener(ThreadSafeArenazConfigListener l);
|
||||
|
||||
// Enables or disables sampling for thread safe arenas.
|
||||
void SetThreadSafeArenazEnabled(bool enabled);
|
||||
void SetThreadSafeArenazEnabledInternal(bool enabled);
|
||||
|
||||
// Returns true if sampling is on, false otherwise.
|
||||
bool IsThreadSafeArenazEnabled();
|
||||
|
||||
// Sets the rate at which thread safe arena will be sampled.
|
||||
void SetThreadSafeArenazSampleParameter(int32_t rate);
|
||||
void SetThreadSafeArenazSampleParameterInternal(int32_t rate);
|
||||
|
||||
// Returns the rate at which thread safe arena will be sampled.
|
||||
int32_t ThreadSafeArenazSampleParameter();
|
||||
|
||||
// Sets a soft max for the number of samples that will be kept.
|
||||
void SetThreadSafeArenazMaxSamples(int32_t max);
|
||||
void SetThreadSafeArenazMaxSamplesInternal(int32_t max);
|
||||
|
||||
// Returns the max number of samples that will be kept.
|
||||
size_t ThreadSafeArenazMaxSamples();
|
||||
|
||||
// Sets the current value for when arenas should be next sampled.
|
||||
void SetThreadSafeArenazGlobalNextSample(int64_t next_sample);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
#endif // GOOGLE_PROTOBUF_SRC_PROTOBUF_ARENAZ_SAMPLER_H__
|
||||
595
libs/protobuf/src/google/protobuf/arenaz_sampler_test.cc
Normal file
595
libs/protobuf/src/google/protobuf/arenaz_sampler_test.cc
Normal file
@@ -0,0 +1,595 @@
|
||||
// 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/arenaz_sampler.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
#if defined(PROTOBUF_ARENAZ_SAMPLE)
|
||||
class ThreadSafeArenaStatsHandlePeer {
|
||||
public:
|
||||
static bool IsSampled(const ThreadSafeArenaStatsHandle& h) {
|
||||
return h.info_ != nullptr;
|
||||
}
|
||||
|
||||
static ThreadSafeArenaStats* GetInfo(ThreadSafeArenaStatsHandle* h) {
|
||||
return h->info_;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<size_t> GetBytesAllocated(ThreadSafeArenazSampler* s) {
|
||||
std::vector<size_t> res;
|
||||
s->Iterate([&](const ThreadSafeArenaStats& info) {
|
||||
for (const auto& block_stats : info.block_histogram) {
|
||||
size_t bytes_allocated =
|
||||
block_stats.bytes_allocated.load(std::memory_order_acquire);
|
||||
if (bytes_allocated != 0) {
|
||||
res.push_back(bytes_allocated);
|
||||
}
|
||||
}
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
ThreadSafeArenaStats* Register(ThreadSafeArenazSampler* s, size_t size,
|
||||
int64_t stride) {
|
||||
auto* info = s->Register(stride);
|
||||
assert(info != nullptr);
|
||||
info->block_histogram[0].bytes_allocated.store(size,
|
||||
std::memory_order_relaxed);
|
||||
return info;
|
||||
}
|
||||
|
||||
#endif // defined(PROTOBUF_ARENAZ_SAMPLE)
|
||||
|
||||
namespace {
|
||||
|
||||
#if defined(PROTOBUF_ARENAZ_SAMPLE)
|
||||
|
||||
TEST(ThreadSafeArenaStatsTest, PrepareForSampling) {
|
||||
ThreadSafeArenaStats info;
|
||||
constexpr int64_t kTestStride = 107;
|
||||
absl::MutexLock l(&info.init_mu);
|
||||
info.PrepareForSampling(kTestStride);
|
||||
|
||||
for (const auto& block_stats : info.block_histogram) {
|
||||
EXPECT_EQ(block_stats.num_allocations.load(std::memory_order_relaxed), 0);
|
||||
EXPECT_EQ(block_stats.bytes_used.load(std::memory_order_relaxed), 0);
|
||||
EXPECT_EQ(block_stats.bytes_allocated.load(std::memory_order_relaxed), 0);
|
||||
EXPECT_EQ(block_stats.bytes_wasted.load(std::memory_order_relaxed), 0);
|
||||
}
|
||||
EXPECT_EQ(info.max_block_size.load(std::memory_order_relaxed), 0);
|
||||
EXPECT_EQ(info.weight, kTestStride);
|
||||
|
||||
for (auto& block_stats : info.block_histogram) {
|
||||
block_stats.num_allocations.store(1, std::memory_order_relaxed);
|
||||
block_stats.bytes_used.store(1, std::memory_order_relaxed);
|
||||
block_stats.bytes_allocated.store(1, std::memory_order_relaxed);
|
||||
block_stats.bytes_wasted.store(1, std::memory_order_relaxed);
|
||||
}
|
||||
info.max_block_size.store(1, std::memory_order_relaxed);
|
||||
|
||||
info.PrepareForSampling(2 * kTestStride);
|
||||
for (auto& block_stats : info.block_histogram) {
|
||||
EXPECT_EQ(block_stats.num_allocations.load(std::memory_order_relaxed), 0);
|
||||
EXPECT_EQ(block_stats.bytes_used.load(std::memory_order_relaxed), 0);
|
||||
EXPECT_EQ(block_stats.bytes_allocated.load(std::memory_order_relaxed), 0);
|
||||
EXPECT_EQ(block_stats.bytes_wasted.load(std::memory_order_relaxed), 0);
|
||||
}
|
||||
EXPECT_EQ(info.max_block_size.load(std::memory_order_relaxed), 0);
|
||||
EXPECT_EQ(info.weight, 2 * kTestStride);
|
||||
}
|
||||
|
||||
TEST(ThreadSafeArenaStatsTest, FindBin) {
|
||||
size_t current_bin = 0;
|
||||
size_t bytes = 1;
|
||||
while (current_bin < ThreadSafeArenaStats::kBlockHistogramBins - 1) {
|
||||
size_t next_bin = ThreadSafeArenaStats::FindBin(bytes);
|
||||
if (next_bin != current_bin) {
|
||||
// Test the bins increase linearly.
|
||||
EXPECT_EQ(next_bin, current_bin + 1);
|
||||
// Test the bins change only at values of the form 2^k + 1.
|
||||
EXPECT_EQ(absl::popcount(bytes - 1), 1);
|
||||
current_bin = next_bin;
|
||||
}
|
||||
++bytes;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ThreadSafeArenaStatsTest, MinMaxBlockSizeForBin) {
|
||||
std::pair<size_t, size_t> current_limits =
|
||||
ThreadSafeArenaStats::MinMaxBlockSizeForBin(0);
|
||||
EXPECT_EQ(current_limits.first, 1);
|
||||
EXPECT_LT(current_limits.first, current_limits.second);
|
||||
for (size_t i = 1; i < ThreadSafeArenaStats::kBlockHistogramBins; ++i) {
|
||||
std::pair<size_t, size_t> next_limits =
|
||||
ThreadSafeArenaStats::MinMaxBlockSizeForBin(i);
|
||||
EXPECT_LT(next_limits.first, next_limits.second);
|
||||
// Test the limits do not have gaps.
|
||||
EXPECT_EQ(next_limits.first, current_limits.second + 1);
|
||||
if (i != ThreadSafeArenaStats::kBlockHistogramBins - 1) {
|
||||
EXPECT_EQ(next_limits.second, 2 * current_limits.second);
|
||||
}
|
||||
current_limits = next_limits;
|
||||
}
|
||||
// Test the limits cover the entire range possible.
|
||||
EXPECT_EQ(current_limits.second, std::numeric_limits<size_t>::max());
|
||||
}
|
||||
|
||||
TEST(ThreadSafeArenaStatsTest, RecordAllocateSlow) {
|
||||
ThreadSafeArenaStats info;
|
||||
constexpr int64_t kTestStride = 458;
|
||||
absl::MutexLock l(&info.init_mu);
|
||||
info.PrepareForSampling(kTestStride);
|
||||
RecordAllocateSlow(&info, /*requested=*/0, /*allocated=*/128, /*wasted=*/0);
|
||||
EXPECT_EQ(
|
||||
info.block_histogram[0].num_allocations.load(std::memory_order_relaxed),
|
||||
1);
|
||||
EXPECT_EQ(info.block_histogram[0].bytes_used.load(std::memory_order_relaxed),
|
||||
0);
|
||||
EXPECT_EQ(
|
||||
info.block_histogram[0].bytes_allocated.load(std::memory_order_relaxed),
|
||||
128);
|
||||
EXPECT_EQ(
|
||||
info.block_histogram[0].bytes_wasted.load(std::memory_order_relaxed), 0);
|
||||
EXPECT_EQ(info.max_block_size.load(std::memory_order_relaxed), 128);
|
||||
RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/256,
|
||||
/*wasted=*/28);
|
||||
EXPECT_EQ(info.block_histogram[0].bytes_used.load(std::memory_order_relaxed),
|
||||
100);
|
||||
EXPECT_EQ(
|
||||
info.block_histogram[0].bytes_wasted.load(std::memory_order_relaxed), 28);
|
||||
EXPECT_EQ(
|
||||
info.block_histogram[1].num_allocations.load(std::memory_order_relaxed),
|
||||
1);
|
||||
EXPECT_EQ(
|
||||
info.block_histogram[1].bytes_allocated.load(std::memory_order_relaxed),
|
||||
256);
|
||||
EXPECT_EQ(info.max_block_size.load(std::memory_order_relaxed), 256);
|
||||
}
|
||||
|
||||
TEST(ThreadSafeArenaStatsTest, RecordAllocateSlowMaxBlockSizeTest) {
|
||||
ThreadSafeArenaStats info;
|
||||
constexpr int64_t kTestStride = 458;
|
||||
absl::MutexLock l(&info.init_mu);
|
||||
info.PrepareForSampling(kTestStride);
|
||||
RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/128, /*wasted=*/0);
|
||||
EXPECT_EQ(info.max_block_size.load(std::memory_order_relaxed), 128);
|
||||
RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/256,
|
||||
/*wasted=*/28);
|
||||
EXPECT_EQ(info.max_block_size.load(std::memory_order_relaxed), 256);
|
||||
RecordAllocateSlow(&info, /*requested=*/100, /*allocated=*/128,
|
||||
/*wasted=*/28);
|
||||
EXPECT_EQ(info.max_block_size.load(std::memory_order_relaxed), 256);
|
||||
}
|
||||
|
||||
TEST(ThreadSafeArenazSamplerTest, SamplingCorrectness) {
|
||||
SetThreadSafeArenazEnabled(true);
|
||||
for (int p = 0; p <= 15; ++p) {
|
||||
SetThreadSafeArenazSampleParameter(1 << p);
|
||||
SetThreadSafeArenazGlobalNextSample(1 << p);
|
||||
const int kTrials = 1000 << p;
|
||||
std::vector<ThreadSafeArenaStatsHandle> hv;
|
||||
for (int i = 0; i < kTrials; ++i) {
|
||||
ThreadSafeArenaStatsHandle h = Sample();
|
||||
if (h.MutableStats() != nullptr) hv.push_back(std::move(h));
|
||||
}
|
||||
// Ideally samples << p should be very close to kTrials. But we keep a
|
||||
// factor of two guard band.
|
||||
EXPECT_GE(hv.size() << p, kTrials / 2);
|
||||
EXPECT_LE(hv.size() << p, 2 * kTrials);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ThreadSafeArenazSamplerTest, SmallSampleParameter) {
|
||||
SetThreadSafeArenazEnabled(true);
|
||||
SetThreadSafeArenazSampleParameter(100);
|
||||
constexpr int64_t kTestStride = 0;
|
||||
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
SamplingState sampling_state = {kTestStride, kTestStride};
|
||||
ThreadSafeArenaStats* sample = SampleSlow(sampling_state);
|
||||
EXPECT_GT(sampling_state.next_sample, 0);
|
||||
EXPECT_NE(sample, nullptr);
|
||||
UnsampleSlow(sample);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ThreadSafeArenazSamplerTest, LargeSampleParameter) {
|
||||
SetThreadSafeArenazEnabled(true);
|
||||
SetThreadSafeArenazSampleParameter(std::numeric_limits<int32_t>::max());
|
||||
constexpr int64_t kTestStride = 0;
|
||||
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
SamplingState sampling_state = {kTestStride, kTestStride};
|
||||
ThreadSafeArenaStats* sample = SampleSlow(sampling_state);
|
||||
EXPECT_GT(sampling_state.next_sample, 0);
|
||||
EXPECT_NE(sample, nullptr);
|
||||
UnsampleSlow(sample);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ThreadSafeArenazSamplerTest, Sample) {
|
||||
SetThreadSafeArenazEnabled(true);
|
||||
SetThreadSafeArenazSampleParameter(100);
|
||||
SetThreadSafeArenazGlobalNextSample(0);
|
||||
int64_t num_sampled = 0;
|
||||
int64_t total = 0;
|
||||
double sample_rate = 0.0;
|
||||
for (int i = 0; i < 1000000; ++i) {
|
||||
ThreadSafeArenaStatsHandle h = Sample();
|
||||
++total;
|
||||
if (ThreadSafeArenaStatsHandlePeer::IsSampled(h)) {
|
||||
++num_sampled;
|
||||
}
|
||||
sample_rate = static_cast<double>(num_sampled) / total;
|
||||
if (0.005 < sample_rate && sample_rate < 0.015) break;
|
||||
}
|
||||
EXPECT_NEAR(sample_rate, 0.01, 0.005);
|
||||
}
|
||||
|
||||
TEST(ThreadSafeArenazSamplerTest, Handle) {
|
||||
auto& sampler = GlobalThreadSafeArenazSampler();
|
||||
constexpr int64_t kTestStride = 17;
|
||||
ThreadSafeArenaStatsHandle h(sampler.Register(kTestStride));
|
||||
auto* info = ThreadSafeArenaStatsHandlePeer::GetInfo(&h);
|
||||
info->block_histogram[0].bytes_allocated.store(0x12345678,
|
||||
std::memory_order_relaxed);
|
||||
|
||||
bool found = false;
|
||||
sampler.Iterate([&](const ThreadSafeArenaStats& h) {
|
||||
if (&h == info) {
|
||||
EXPECT_EQ(
|
||||
h.block_histogram[0].bytes_allocated.load(std::memory_order_relaxed),
|
||||
0x12345678);
|
||||
EXPECT_EQ(h.weight, kTestStride);
|
||||
found = true;
|
||||
}
|
||||
});
|
||||
EXPECT_TRUE(found);
|
||||
|
||||
h = ThreadSafeArenaStatsHandle();
|
||||
found = false;
|
||||
sampler.Iterate([&](const ThreadSafeArenaStats& h) {
|
||||
if (&h == info) {
|
||||
// this will only happen if some other thread has resurrected the info
|
||||
// the old handle was using.
|
||||
if (h.block_histogram[0].bytes_allocated.load(
|
||||
std::memory_order_relaxed) == 0x12345678) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
EXPECT_FALSE(found);
|
||||
}
|
||||
|
||||
TEST(ThreadSafeArenazSamplerTest, Registration) {
|
||||
ThreadSafeArenazSampler sampler;
|
||||
constexpr int64_t kTestStride = 100;
|
||||
auto* info1 = Register(&sampler, 1, kTestStride);
|
||||
EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(1));
|
||||
|
||||
auto* info2 = Register(&sampler, 2, kTestStride);
|
||||
EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(1, 2));
|
||||
info1->block_histogram[0].bytes_allocated.store(3, std::memory_order_relaxed);
|
||||
EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(3, 2));
|
||||
|
||||
sampler.Unregister(info1);
|
||||
sampler.Unregister(info2);
|
||||
}
|
||||
|
||||
TEST(ThreadSafeArenazSamplerTest, Unregistration) {
|
||||
ThreadSafeArenazSampler sampler;
|
||||
std::vector<ThreadSafeArenaStats*> infos;
|
||||
constexpr int64_t kTestStride = 200;
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
infos.push_back(Register(&sampler, i + 1, kTestStride));
|
||||
}
|
||||
EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(1, 2, 3));
|
||||
|
||||
sampler.Unregister(infos[1]);
|
||||
EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(1, 3));
|
||||
|
||||
infos.push_back(Register(&sampler, 3, kTestStride));
|
||||
infos.push_back(Register(&sampler, 4, kTestStride));
|
||||
EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(1, 3, 3, 4));
|
||||
sampler.Unregister(infos[3]);
|
||||
EXPECT_THAT(GetBytesAllocated(&sampler), UnorderedElementsAre(1, 3, 4));
|
||||
|
||||
sampler.Unregister(infos[0]);
|
||||
sampler.Unregister(infos[2]);
|
||||
sampler.Unregister(infos[4]);
|
||||
EXPECT_THAT(GetBytesAllocated(&sampler), IsEmpty());
|
||||
}
|
||||
|
||||
TEST(ThreadSafeArenazSamplerTest, MultiThreaded) {
|
||||
ThreadSafeArenazSampler sampler;
|
||||
absl::Notification stop;
|
||||
ThreadPool pool(10);
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
const int64_t sampling_stride = 11 + i % 3;
|
||||
pool.Schedule([&sampler, &stop, sampling_stride]() {
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
|
||||
std::vector<ThreadSafeArenaStats*> infoz;
|
||||
while (!stop.HasBeenNotified()) {
|
||||
if (infoz.empty()) {
|
||||
infoz.push_back(sampler.Register(sampling_stride));
|
||||
}
|
||||
switch (std::uniform_int_distribution<>(0, 1)(gen)) {
|
||||
case 0: {
|
||||
infoz.push_back(sampler.Register(sampling_stride));
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
size_t p =
|
||||
std::uniform_int_distribution<>(0, infoz.size() - 1)(gen);
|
||||
ThreadSafeArenaStats* info = infoz[p];
|
||||
infoz[p] = infoz.back();
|
||||
infoz.pop_back();
|
||||
EXPECT_EQ(info->weight, sampling_stride);
|
||||
sampler.Unregister(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// The threads will hammer away. Give it a little bit of time for tsan to
|
||||
// spot errors.
|
||||
absl::SleepFor(absl::Seconds(3));
|
||||
stop.Notify();
|
||||
}
|
||||
|
||||
TEST(ThreadSafeArenazSamplerTest, Callback) {
|
||||
ThreadSafeArenazSampler sampler;
|
||||
constexpr int64_t kTestStride = 203;
|
||||
|
||||
auto* info1 = Register(&sampler, 1, kTestStride);
|
||||
auto* info2 = Register(&sampler, 2, kTestStride);
|
||||
|
||||
static const ThreadSafeArenaStats* expected;
|
||||
|
||||
auto callback = [](const ThreadSafeArenaStats& info) {
|
||||
// We can't use `info` outside of this callback because the object will be
|
||||
// disposed as soon as we return from here.
|
||||
EXPECT_EQ(&info, expected);
|
||||
};
|
||||
|
||||
// Set the callback.
|
||||
EXPECT_EQ(sampler.SetDisposeCallback(callback), nullptr);
|
||||
expected = info1;
|
||||
sampler.Unregister(info1);
|
||||
|
||||
// Unset the callback.
|
||||
EXPECT_EQ(callback, sampler.SetDisposeCallback(nullptr));
|
||||
expected = nullptr; // no more calls.
|
||||
sampler.Unregister(info2);
|
||||
}
|
||||
|
||||
TEST(ThreadSafeArenazSamplerTest, InitialBlockReportsZeroUsedAndWasted) {
|
||||
SetThreadSafeArenazEnabled(true);
|
||||
// Setting 1 as the parameter value means one in every two arenas would be
|
||||
// sampled, on average.
|
||||
int32_t oldparam = ThreadSafeArenazSampleParameter();
|
||||
SetThreadSafeArenazSampleParameter(1);
|
||||
SetThreadSafeArenazGlobalNextSample(0);
|
||||
constexpr int kSize = 571;
|
||||
int count_found_allocation = 0;
|
||||
auto& sampler = GlobalThreadSafeArenazSampler();
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
char block[kSize];
|
||||
google::protobuf::Arena arena(/*initial_block=*/block, /*initial_block_size=*/kSize);
|
||||
sampler.Iterate([&](const ThreadSafeArenaStats& h) {
|
||||
const auto& histbin =
|
||||
h.block_histogram[ThreadSafeArenaStats::FindBin(kSize)];
|
||||
if (histbin.bytes_allocated.load(std::memory_order_relaxed) == kSize) {
|
||||
count_found_allocation++;
|
||||
EXPECT_EQ(histbin.bytes_used, 0);
|
||||
EXPECT_EQ(histbin.bytes_wasted, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
EXPECT_GT(count_found_allocation, 0);
|
||||
SetThreadSafeArenazSampleParameter(oldparam);
|
||||
}
|
||||
|
||||
class ThreadSafeArenazSamplerTestThread : public Thread {
|
||||
protected:
|
||||
void Run() override {
|
||||
google::protobuf::ArenaSafeUniquePtr<
|
||||
protobuf_test_messages::proto2::TestAllTypesProto2>
|
||||
message = google::protobuf::MakeArenaSafeUnique<
|
||||
protobuf_test_messages::proto2::TestAllTypesProto2>(arena_);
|
||||
GOOGLE_CHECK(message != nullptr);
|
||||
// Signal that a message on the arena has been created. This should create
|
||||
// a SerialArena for this thread.
|
||||
if (barrier_->Block()) {
|
||||
delete barrier_;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
ThreadSafeArenazSamplerTestThread(const thread::Options& options,
|
||||
absl::string_view name,
|
||||
google::protobuf::Arena* arena,
|
||||
absl::Barrier* barrier)
|
||||
: Thread(options, name), arena_(arena), barrier_(barrier) {}
|
||||
|
||||
private:
|
||||
google::protobuf::Arena* arena_;
|
||||
absl::Barrier* barrier_;
|
||||
};
|
||||
|
||||
TEST(ThreadSafeArenazSamplerTest, MultiThread) {
|
||||
SetThreadSafeArenazEnabled(true);
|
||||
// Setting 1 as the parameter value means one in every two arenas would be
|
||||
// sampled, on average.
|
||||
int32_t oldparam = ThreadSafeArenazSampleParameter();
|
||||
SetThreadSafeArenazSampleParameter(1);
|
||||
SetThreadSafeArenazGlobalNextSample(0);
|
||||
auto& sampler = GlobalThreadSafeArenazSampler();
|
||||
int count = 0;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
const int kNumThreads = 10;
|
||||
absl::Barrier* barrier = new absl::Barrier(kNumThreads + 1);
|
||||
google::protobuf::Arena arena;
|
||||
thread::Options options;
|
||||
options.set_joinable(true);
|
||||
std::vector<std::unique_ptr<ThreadSafeArenazSamplerTestThread>> threads;
|
||||
for (int i = 0; i < kNumThreads; i++) {
|
||||
auto t = std::make_unique<ThreadSafeArenazSamplerTestThread>(
|
||||
options, absl::StrCat("thread", i), &arena, barrier);
|
||||
t->Start();
|
||||
threads.push_back(std::move(t));
|
||||
}
|
||||
// Wait till each thread has created a message on the arena.
|
||||
if (barrier->Block()) {
|
||||
delete barrier;
|
||||
}
|
||||
sampler.Iterate([&](const ThreadSafeArenaStats& h) { ++count; });
|
||||
for (int i = 0; i < kNumThreads; i++) {
|
||||
threads[i]->Join();
|
||||
}
|
||||
}
|
||||
EXPECT_GT(count, 0);
|
||||
SetThreadSafeArenazSampleParameter(oldparam);
|
||||
}
|
||||
|
||||
class SampleFirstArenaThread : public Thread {
|
||||
protected:
|
||||
void Run() override {
|
||||
google::protobuf::Arena arena;
|
||||
google::protobuf::ArenaSafeUniquePtr<
|
||||
protobuf_test_messages::proto2::TestAllTypesProto2>
|
||||
message = google::protobuf::MakeArenaSafeUnique<
|
||||
protobuf_test_messages::proto2::TestAllTypesProto2>(&arena);
|
||||
GOOGLE_CHECK(message != nullptr);
|
||||
arena_created_.Notify();
|
||||
samples_counted_.WaitForNotification();
|
||||
}
|
||||
|
||||
public:
|
||||
explicit SampleFirstArenaThread(const thread::Options& options)
|
||||
: Thread(options, "SampleFirstArenaThread") {}
|
||||
|
||||
absl::Notification arena_created_;
|
||||
absl::Notification samples_counted_;
|
||||
};
|
||||
|
||||
// Test that the first arena created on a thread may and may not be chosen for
|
||||
// sampling.
|
||||
TEST(ThreadSafeArenazSamplerTest, SampleFirstArena) {
|
||||
SetThreadSafeArenazEnabled(true);
|
||||
auto& sampler = GlobalThreadSafeArenazSampler();
|
||||
|
||||
enum class SampleResult {
|
||||
kSampled,
|
||||
kUnsampled,
|
||||
kSpoiled,
|
||||
};
|
||||
|
||||
auto count_samples = [&]() {
|
||||
int count = 0;
|
||||
sampler.Iterate([&](const ThreadSafeArenaStats& h) { ++count; });
|
||||
return count;
|
||||
};
|
||||
|
||||
auto run_sample_experiment = [&]() {
|
||||
int before = count_samples();
|
||||
thread::Options options;
|
||||
options.set_joinable(true);
|
||||
SampleFirstArenaThread t(options);
|
||||
t.Start();
|
||||
t.arena_created_.WaitForNotification();
|
||||
int during = count_samples();
|
||||
t.samples_counted_.Notify();
|
||||
t.Join();
|
||||
int after = count_samples();
|
||||
|
||||
// If we didn't get back where we were, some other thread may have
|
||||
// created an arena and produced an invalid experiment run.
|
||||
if (before != after) return SampleResult::kSpoiled;
|
||||
|
||||
switch (during - before) {
|
||||
case 1:
|
||||
return SampleResult::kSampled;
|
||||
case 0:
|
||||
return SampleResult::kUnsampled;
|
||||
default:
|
||||
return SampleResult::kSpoiled;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr int kTrials = 10000;
|
||||
bool sampled = false;
|
||||
bool unsampled = false;
|
||||
for (int i = 0; i < kTrials; ++i) {
|
||||
switch (run_sample_experiment()) {
|
||||
case SampleResult::kSampled:
|
||||
sampled = true;
|
||||
break;
|
||||
case SampleResult::kUnsampled:
|
||||
unsampled = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// This is the success criteria for the entire test. At some point
|
||||
// we sampled the first arena and at some point we did not.
|
||||
if (sampled && unsampled) return;
|
||||
}
|
||||
EXPECT_TRUE(sampled);
|
||||
EXPECT_TRUE(unsampled);
|
||||
}
|
||||
#endif // defined(PROTOBUF_ARENAZ_SAMPLE)
|
||||
|
||||
} // namespace
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
375
libs/protobuf/src/google/protobuf/compiler/BUILD.bazel
Normal file
375
libs/protobuf/src/google/protobuf/compiler/BUILD.bazel
Normal file
@@ -0,0 +1,375 @@
|
||||
################################################################################
|
||||
# Protocol Buffers Compiler
|
||||
################################################################################
|
||||
|
||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
|
||||
load(
|
||||
"@rules_pkg//:mappings.bzl",
|
||||
"pkg_attributes",
|
||||
"pkg_files",
|
||||
"strip_prefix",
|
||||
)
|
||||
load("@rules_proto//proto:defs.bzl", "proto_library")
|
||||
load("//build_defs:arch_tests.bzl", "aarch64_test", "x86_64_test")
|
||||
load("//build_defs:cpp_opts.bzl", "COPTS", "LINK_OPTS", "PROTOC_LINK_OPTS")
|
||||
|
||||
proto_library(
|
||||
name = "plugin_proto",
|
||||
srcs = ["plugin.proto"],
|
||||
visibility = [
|
||||
"//:__pkg__",
|
||||
"//pkg:__pkg__",
|
||||
],
|
||||
deps = ["//:descriptor_proto"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "importer",
|
||||
srcs = [
|
||||
"importer.cc",
|
||||
"parser.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"importer.h",
|
||||
"parser.h",
|
||||
],
|
||||
copts = COPTS,
|
||||
include_prefix = "google/protobuf/compiler",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//src/google/protobuf:protobuf_nowkt",
|
||||
"@com_google_absl//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "code_generator",
|
||||
srcs = [
|
||||
"code_generator.cc",
|
||||
"plugin.cc",
|
||||
"plugin.pb.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"code_generator.h",
|
||||
"plugin.h",
|
||||
"plugin.pb.h",
|
||||
"scc.h",
|
||||
],
|
||||
copts = COPTS,
|
||||
include_prefix = "google/protobuf/compiler",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//src/google/protobuf:protobuf_nowkt",
|
||||
"@com_google_absl//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "command_line_interface",
|
||||
srcs = [
|
||||
"command_line_interface.cc",
|
||||
"subprocess.cc",
|
||||
"zip_writer.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"command_line_interface.h",
|
||||
"subprocess.h",
|
||||
"zip_writer.h",
|
||||
],
|
||||
copts = COPTS,
|
||||
include_prefix = "google/protobuf/compiler",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":code_generator",
|
||||
":importer",
|
||||
"//src/google/protobuf:protobuf_nowkt",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/strings:str_format",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "protoc_lib_nowkt",
|
||||
srcs = [
|
||||
"main.cc",
|
||||
],
|
||||
copts = COPTS,
|
||||
deps = [
|
||||
":code_generator",
|
||||
":command_line_interface",
|
||||
":importer",
|
||||
"//src/google/protobuf:protobuf_nowkt",
|
||||
"//src/google/protobuf/compiler/cpp",
|
||||
"//src/google/protobuf/compiler/csharp",
|
||||
"//src/google/protobuf/compiler/java",
|
||||
"//src/google/protobuf/compiler/objectivec",
|
||||
"//src/google/protobuf/compiler/php",
|
||||
"//src/google/protobuf/compiler/python",
|
||||
"//src/google/protobuf/compiler/ruby",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "protoc_nowkt",
|
||||
copts = COPTS,
|
||||
linkopts = LINK_OPTS + PROTOC_LINK_OPTS,
|
||||
visibility = [
|
||||
"//src/google/protobuf:__pkg__",
|
||||
],
|
||||
deps = [":protoc_lib_nowkt"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "protoc_lib",
|
||||
copts = COPTS,
|
||||
visibility = [
|
||||
"//:__pkg__",
|
||||
"//pkg:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":protoc_lib_nowkt",
|
||||
"//:protobuf",
|
||||
],
|
||||
)
|
||||
|
||||
# Note: this is an alias for now. In the future, this rule will become the
|
||||
# cc_binary for protoc, and //:protoc will become an alias.
|
||||
alias(
|
||||
name = "protoc",
|
||||
actual = "//:protoc",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
# Test that the protoc binary is built for the correct architecture.
|
||||
aarch64_test(
|
||||
name = "protoc_aarch64_test",
|
||||
bazel_binaries = ["//:protoc"],
|
||||
)
|
||||
|
||||
x86_64_test(
|
||||
name = "protoc_x86_64_test",
|
||||
bazel_binaries = ["//:protoc"],
|
||||
)
|
||||
|
||||
################################################################################
|
||||
# Tests and support libraries
|
||||
################################################################################
|
||||
|
||||
cc_library(
|
||||
name = "annotation_test_util",
|
||||
testonly = 1,
|
||||
srcs = ["annotation_test_util.cc"],
|
||||
hdrs = ["annotation_test_util.h"],
|
||||
copts = COPTS,
|
||||
strip_include_prefix = "/src",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":code_generator",
|
||||
":command_line_interface",
|
||||
"//:protobuf",
|
||||
"//src/google/protobuf/io",
|
||||
"//src/google/protobuf/testing",
|
||||
],
|
||||
)
|
||||
|
||||
################################################################################
|
||||
# Tests
|
||||
################################################################################
|
||||
|
||||
filegroup(
|
||||
name = "plugin_proto_srcs",
|
||||
testonly = 1,
|
||||
srcs = [
|
||||
"plugin.pb.cc",
|
||||
"plugin.pb.h",
|
||||
"plugin.proto",
|
||||
],
|
||||
visibility = [
|
||||
"//src/google/protobuf/compiler/cpp:__pkg__",
|
||||
],
|
||||
)
|
||||
|
||||
exports_files(
|
||||
srcs = ["plugin.proto"],
|
||||
visibility = ["//:__pkg__"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "mock_code_generator",
|
||||
testonly = 1,
|
||||
srcs = ["mock_code_generator.cc"],
|
||||
hdrs = ["mock_code_generator.h"],
|
||||
copts = COPTS,
|
||||
strip_include_prefix = "/src",
|
||||
visibility = ["//pkg:__pkg__"],
|
||||
deps = [
|
||||
":code_generator",
|
||||
"//src/google/protobuf/io",
|
||||
"//src/google/protobuf/stubs",
|
||||
"//src/google/protobuf/testing",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "test_plugin",
|
||||
testonly = 1,
|
||||
srcs = ["test_plugin.cc"],
|
||||
copts = COPTS,
|
||||
deps = [
|
||||
":code_generator",
|
||||
":mock_code_generator",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "command_line_interface_unittest",
|
||||
srcs = ["command_line_interface_unittest.cc"],
|
||||
copts = COPTS + select({
|
||||
"//build_defs:config_msvc": [],
|
||||
"//conditions:default": [
|
||||
"-Wno-deprecated",
|
||||
"-Wno-deprecated-declarations",
|
||||
],
|
||||
}) + [
|
||||
# Note: This only works on Windows with symlinks and runfiles enabled.
|
||||
"-DGOOGLE_PROTOBUF_TEST_PLUGIN_PATH=\\\"$(rootpath :test_plugin)\\\"",
|
||||
],
|
||||
data = [
|
||||
":test_plugin",
|
||||
"//:test_proto_srcs",
|
||||
"//src/google/protobuf:testdata",
|
||||
],
|
||||
deps = [
|
||||
":code_generator",
|
||||
":command_line_interface",
|
||||
":mock_code_generator",
|
||||
"//:protobuf",
|
||||
"//src/google/protobuf/compiler/cpp:names",
|
||||
"//src/google/protobuf:cc_test_protos",
|
||||
"//src/google/protobuf:test_util2",
|
||||
"//src/google/protobuf/io",
|
||||
"//src/google/protobuf/stubs",
|
||||
"//src/google/protobuf/testing",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "importer_unittest",
|
||||
srcs = ["importer_unittest.cc"],
|
||||
copts = COPTS,
|
||||
deps = [
|
||||
":importer",
|
||||
"//:protobuf",
|
||||
"//src/google/protobuf/io",
|
||||
"//src/google/protobuf/stubs",
|
||||
"//src/google/protobuf/testing",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "parser_unittest",
|
||||
srcs = ["parser_unittest.cc"],
|
||||
copts = COPTS + select({
|
||||
"//build_defs:config_msvc": [],
|
||||
"//conditions:default": [
|
||||
"-Wno-deprecated",
|
||||
"-Wno-deprecated-declarations",
|
||||
],
|
||||
}),
|
||||
deps = [
|
||||
":importer",
|
||||
"//:protobuf",
|
||||
"//src/google/protobuf:cc_test_protos",
|
||||
"//src/google/protobuf:test_util2",
|
||||
"//src/google/protobuf/io",
|
||||
"//src/google/protobuf/stubs",
|
||||
"//src/google/protobuf/testing",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
################################################################################
|
||||
# Generates protoc release artifacts.
|
||||
################################################################################
|
||||
|
||||
genrule(
|
||||
name = "protoc_readme",
|
||||
outs = ["readme.txt"],
|
||||
cmd = """
|
||||
echo "Protocol Buffers - Google's data interchange format
|
||||
Copyright 2008 Google Inc.
|
||||
https://developers.google.com/protocol-buffers/
|
||||
This package contains a precompiled binary version of the protocol buffer
|
||||
compiler (protoc). This binary is intended for users who want to use Protocol
|
||||
Buffers in languages other than C++ but do not want to compile protoc
|
||||
themselves. To install, simply place this binary somewhere in your PATH.
|
||||
If you intend to use the included well known types then don't forget to
|
||||
copy the contents of the 'include' directory somewhere as well, for example
|
||||
into '/usr/local/include/'.
|
||||
Please refer to our official github site for more installation instructions:
|
||||
https://github.com/protocolbuffers/protobuf" > $@
|
||||
""",
|
||||
visibility = ["//:__pkg__"],
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = "compiler_plugin_protos_files",
|
||||
srcs = ["plugin.proto"],
|
||||
prefix = "include/google/protobuf/compiler",
|
||||
visibility = ["//pkg:__pkg__"],
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = "protoc_files",
|
||||
srcs = [":protoc"],
|
||||
attributes = pkg_attributes(mode = "0555"),
|
||||
prefix = "bin/",
|
||||
visibility = ["//:__pkg__"],
|
||||
)
|
||||
|
||||
################################################################################
|
||||
# Distribution packaging
|
||||
################################################################################
|
||||
|
||||
pkg_files(
|
||||
name = "dist_files",
|
||||
srcs = glob(["**/*"]),
|
||||
strip_prefix = strip_prefix.from_root(""),
|
||||
visibility = ["//src:__pkg__"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "test_srcs",
|
||||
srcs = glob([
|
||||
"*_test.cc",
|
||||
"*unittest.cc",
|
||||
]) + [
|
||||
"//src/google/protobuf/compiler/cpp:test_srcs",
|
||||
"//src/google/protobuf/compiler/csharp:test_srcs",
|
||||
"//src/google/protobuf/compiler/java:test_srcs",
|
||||
"//src/google/protobuf/compiler/objectivec:test_srcs",
|
||||
"//src/google/protobuf/compiler/php:test_srcs",
|
||||
"//src/google/protobuf/compiler/python:test_srcs",
|
||||
"//src/google/protobuf/compiler/ruby:test_srcs",
|
||||
],
|
||||
visibility = ["//pkg:__pkg__"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "test_plugin_srcs",
|
||||
srcs = ["test_plugin.cc"],
|
||||
visibility = ["//pkg:__pkg__"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "test_proto_srcs",
|
||||
srcs = [
|
||||
"//src/google/protobuf/compiler/cpp:test_proto_srcs",
|
||||
],
|
||||
visibility = ["//pkg:__pkg__"],
|
||||
)
|
||||
@@ -0,0 +1,167 @@
|
||||
// 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/compiler/annotation_test_util.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "google/protobuf/testing/file.h"
|
||||
#include "google/protobuf/testing/file.h"
|
||||
#include "google/protobuf/compiler/code_generator.h"
|
||||
#include "google/protobuf/compiler/command_line_interface.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "google/protobuf/io/zero_copy_stream.h"
|
||||
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
#include "google/protobuf/testing/googletest.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace annotation_test_util {
|
||||
namespace {
|
||||
|
||||
// A CodeGenerator that captures the FileDescriptor it's passed as a
|
||||
// FileDescriptorProto.
|
||||
class DescriptorCapturingGenerator : public CodeGenerator {
|
||||
public:
|
||||
// Does not own file; file must outlive the Generator.
|
||||
explicit DescriptorCapturingGenerator(FileDescriptorProto* file)
|
||||
: file_(file) {}
|
||||
|
||||
bool Generate(const FileDescriptor* file, const std::string& parameter,
|
||||
GeneratorContext* context, std::string* error) const override {
|
||||
file->CopyTo(file_);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
FileDescriptorProto* file_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void AddFile(const std::string& filename, const std::string& data) {
|
||||
GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/" + filename, data,
|
||||
true));
|
||||
}
|
||||
|
||||
bool RunProtoCompiler(const std::string& filename,
|
||||
const std::string& plugin_specific_args,
|
||||
CommandLineInterface* cli, FileDescriptorProto* file) {
|
||||
cli->SetInputsAreProtoPathRelative(true);
|
||||
|
||||
DescriptorCapturingGenerator capturing_generator(file);
|
||||
cli->RegisterGenerator("--capture_out", &capturing_generator, "");
|
||||
|
||||
std::string proto_path = "-I" + TestTempDir();
|
||||
std::string capture_out = "--capture_out=" + TestTempDir();
|
||||
|
||||
const char* argv[] = {"protoc", proto_path.c_str(),
|
||||
plugin_specific_args.c_str(), capture_out.c_str(),
|
||||
filename.c_str()};
|
||||
|
||||
return cli->Run(5, argv) == 0;
|
||||
}
|
||||
|
||||
bool DecodeMetadata(const std::string& path, GeneratedCodeInfo* info) {
|
||||
std::string data;
|
||||
GOOGLE_CHECK_OK(File::GetContents(path, &data, true));
|
||||
io::ArrayInputStream input(data.data(), data.size());
|
||||
return info->ParseFromZeroCopyStream(&input);
|
||||
}
|
||||
|
||||
void FindAnnotationsOnPath(
|
||||
const GeneratedCodeInfo& info, const std::string& source_file,
|
||||
const std::vector<int>& path,
|
||||
std::vector<const GeneratedCodeInfo::Annotation*>* annotations) {
|
||||
for (int i = 0; i < info.annotation_size(); ++i) {
|
||||
const GeneratedCodeInfo::Annotation* annotation = &info.annotation(i);
|
||||
if (annotation->source_file() != source_file ||
|
||||
annotation->path_size() != path.size()) {
|
||||
continue;
|
||||
}
|
||||
int node = 0;
|
||||
for (; node < path.size(); ++node) {
|
||||
if (annotation->path(node) != path[node]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (node == path.size()) {
|
||||
annotations->push_back(annotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const GeneratedCodeInfo::Annotation* FindAnnotationOnPath(
|
||||
const GeneratedCodeInfo& info, const std::string& source_file,
|
||||
const std::vector<int>& path) {
|
||||
std::vector<const GeneratedCodeInfo::Annotation*> annotations;
|
||||
FindAnnotationsOnPath(info, source_file, path, &annotations);
|
||||
if (annotations.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
return annotations[0];
|
||||
}
|
||||
|
||||
bool AtLeastOneAnnotationMatchesSubstring(
|
||||
const std::string& file_content,
|
||||
const std::vector<const GeneratedCodeInfo::Annotation*>& annotations,
|
||||
const std::string& expected_text) {
|
||||
for (std::vector<const GeneratedCodeInfo::Annotation*>::const_iterator
|
||||
i = annotations.begin(),
|
||||
e = annotations.end();
|
||||
i != e; ++i) {
|
||||
const GeneratedCodeInfo::Annotation* annotation = *i;
|
||||
uint32_t begin = annotation->begin();
|
||||
uint32_t end = annotation->end();
|
||||
if (end < begin || end > file_content.size()) {
|
||||
return false;
|
||||
}
|
||||
if (file_content.substr(begin, end - begin) == expected_text) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AnnotationMatchesSubstring(const std::string& file_content,
|
||||
const GeneratedCodeInfo::Annotation* annotation,
|
||||
const std::string& expected_text) {
|
||||
std::vector<const GeneratedCodeInfo::Annotation*> annotations;
|
||||
annotations.push_back(annotation);
|
||||
return AtLeastOneAnnotationMatchesSubstring(file_content, annotations,
|
||||
expected_text);
|
||||
}
|
||||
} // namespace annotation_test_util
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
@@ -0,0 +1,115 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_ANNOTATION_TEST_UTIL_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_ANNOTATION_TEST_UTIL_H__
|
||||
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
#include "google/protobuf/testing/googletest.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// Utilities that assist in writing tests for generator annotations.
|
||||
// See java/internal/annotation_unittest.cc for an example.
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace annotation_test_util {
|
||||
|
||||
// Struct that contains the file generated from a .proto file and its
|
||||
// GeneratedCodeInfo. For example, the Java generator will fill this struct
|
||||
// (for some 'foo.proto') with:
|
||||
// file_path = "Foo.java"
|
||||
// file_content = content of Foo.java
|
||||
// file_info = parsed content of Foo.java.pb.meta
|
||||
struct ExpectedOutput {
|
||||
std::string file_path;
|
||||
std::string file_content;
|
||||
GeneratedCodeInfo file_info;
|
||||
explicit ExpectedOutput(const std::string& file_path)
|
||||
: file_path(file_path) {}
|
||||
};
|
||||
|
||||
// Creates a file with name `filename` and content `data` in temp test
|
||||
// directory.
|
||||
void AddFile(const std::string& filename, const std::string& data);
|
||||
|
||||
// Runs proto compiler. Captures proto file structure in FileDescriptorProto.
|
||||
// Files will be generated in TestTempDir() folder. Callers of this
|
||||
// function must read generated files themselves.
|
||||
//
|
||||
// filename: source .proto file used to generate code.
|
||||
// plugin_specific_args: command line arguments specific to current generator.
|
||||
// For Java, this value might be "--java_out=annotate_code:test_temp_dir"
|
||||
// cli: instance of command line interface to run generator. See Java's
|
||||
// annotation_unittest.cc for an example of how to initialize it.
|
||||
// file: output parameter, will be set to the descriptor of the proto file
|
||||
// specified in filename.
|
||||
bool RunProtoCompiler(const std::string& filename,
|
||||
const std::string& plugin_specific_args,
|
||||
CommandLineInterface* cli, FileDescriptorProto* file);
|
||||
|
||||
bool DecodeMetadata(const std::string& path, GeneratedCodeInfo* info);
|
||||
|
||||
// Finds all of the Annotations for a given source file and path.
|
||||
// See Location.path in https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto for
|
||||
// explanation of what path vector is.
|
||||
void FindAnnotationsOnPath(
|
||||
const GeneratedCodeInfo& info, const std::string& source_file,
|
||||
const std::vector<int>& path,
|
||||
std::vector<const GeneratedCodeInfo::Annotation*>* annotations);
|
||||
|
||||
// Finds the Annotation for a given source file and path (or returns null if it
|
||||
// couldn't). If there are several annotations for given path, returns the first
|
||||
// one. See Location.path in
|
||||
// https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto for explanation of what path
|
||||
// vector is.
|
||||
const GeneratedCodeInfo::Annotation* FindAnnotationOnPath(
|
||||
const GeneratedCodeInfo& info, const std::string& source_file,
|
||||
const std::vector<int>& path);
|
||||
|
||||
// Returns true if at least one of the provided annotations covers a given
|
||||
// substring in file_content.
|
||||
bool AtLeastOneAnnotationMatchesSubstring(
|
||||
const std::string& file_content,
|
||||
const std::vector<const GeneratedCodeInfo::Annotation*>& annotations,
|
||||
const std::string& expected_text);
|
||||
|
||||
// Returns true if the provided annotation covers a given substring in
|
||||
// file_content.
|
||||
bool AnnotationMatchesSubstring(const std::string& file_content,
|
||||
const GeneratedCodeInfo::Annotation* annotation,
|
||||
const std::string& expected_text);
|
||||
|
||||
} // namespace annotation_test_util
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_ANNOTATION_TEST_UTIL_H__
|
||||
138
libs/protobuf/src/google/protobuf/compiler/code_generator.cc
Normal file
138
libs/protobuf/src/google/protobuf/compiler/code_generator.cc
Normal file
@@ -0,0 +1,138 @@
|
||||
// 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/compiler/code_generator.h"
|
||||
|
||||
#include "google/protobuf/stubs/logging.h"
|
||||
#include "google/protobuf/stubs/common.h"
|
||||
#include "google/protobuf/compiler/plugin.pb.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "absl/strings/str_split.h"
|
||||
#include "absl/strings/strip.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
|
||||
CodeGenerator::~CodeGenerator() {}
|
||||
|
||||
bool CodeGenerator::GenerateAll(const std::vector<const FileDescriptor*>& files,
|
||||
const std::string& parameter,
|
||||
GeneratorContext* generator_context,
|
||||
std::string* error) const {
|
||||
// Default implementation is just to call the per file method, and prefix any
|
||||
// error string with the file to provide context.
|
||||
bool succeeded = true;
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
const FileDescriptor* file = files[i];
|
||||
succeeded = Generate(file, parameter, generator_context, error);
|
||||
if (!succeeded && error && error->empty()) {
|
||||
*error =
|
||||
"Code generator returned false but provided no error "
|
||||
"description.";
|
||||
}
|
||||
if (error && !error->empty()) {
|
||||
*error = file->name() + ": " + *error;
|
||||
break;
|
||||
}
|
||||
if (!succeeded) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
GeneratorContext::~GeneratorContext() {}
|
||||
|
||||
io::ZeroCopyOutputStream* GeneratorContext::OpenForAppend(
|
||||
const std::string& filename) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
io::ZeroCopyOutputStream* GeneratorContext::OpenForInsert(
|
||||
const std::string& filename, const std::string& insertion_point) {
|
||||
GOOGLE_LOG(FATAL) << "This GeneratorContext does not support insertion.";
|
||||
return nullptr; // make compiler happy
|
||||
}
|
||||
|
||||
io::ZeroCopyOutputStream* GeneratorContext::OpenForInsertWithGeneratedCodeInfo(
|
||||
const std::string& filename, const std::string& insertion_point,
|
||||
const google::protobuf::GeneratedCodeInfo& /*info*/) {
|
||||
return OpenForInsert(filename, insertion_point);
|
||||
}
|
||||
|
||||
void GeneratorContext::ListParsedFiles(
|
||||
std::vector<const FileDescriptor*>* output) {
|
||||
GOOGLE_LOG(FATAL) << "This GeneratorContext does not support ListParsedFiles";
|
||||
}
|
||||
|
||||
void GeneratorContext::GetCompilerVersion(Version* version) const {
|
||||
version->set_major(GOOGLE_PROTOBUF_VERSION / 1000000);
|
||||
version->set_minor(GOOGLE_PROTOBUF_VERSION / 1000 % 1000);
|
||||
version->set_patch(GOOGLE_PROTOBUF_VERSION % 1000);
|
||||
version->set_suffix(GOOGLE_PROTOBUF_VERSION_SUFFIX);
|
||||
}
|
||||
|
||||
// Parses a set of comma-delimited name/value pairs.
|
||||
void ParseGeneratorParameter(
|
||||
const std::string& text,
|
||||
std::vector<std::pair<std::string, std::string> >* output) {
|
||||
std::vector<std::string> parts = absl::StrSplit(text, ",", absl::SkipEmpty());
|
||||
|
||||
for (int i = 0; i < parts.size(); i++) {
|
||||
std::string::size_type equals_pos = parts[i].find_first_of('=');
|
||||
std::pair<std::string, std::string> value;
|
||||
if (equals_pos == std::string::npos) {
|
||||
value.first = parts[i];
|
||||
value.second = "";
|
||||
} else {
|
||||
value.first = parts[i].substr(0, equals_pos);
|
||||
value.second = parts[i].substr(equals_pos + 1);
|
||||
}
|
||||
output->push_back(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Strips ".proto" or ".protodevel" from the end of a filename.
|
||||
std::string StripProto(const std::string& filename) {
|
||||
if (absl::EndsWith(filename, ".protodevel")) {
|
||||
return std::string(absl::StripSuffix(filename, ".protodevel"));
|
||||
} else {
|
||||
return std::string(absl::StripSuffix(filename, ".proto"));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
206
libs/protobuf/src/google/protobuf/compiler/code_generator.h
Normal file
206
libs/protobuf/src/google/protobuf/compiler/code_generator.h
Normal file
@@ -0,0 +1,206 @@
|
||||
// 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.
|
||||
//
|
||||
// Defines the abstract interface implemented by each of the language-specific
|
||||
// code generators.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "google/protobuf/port.h"
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
namespace io {
|
||||
class ZeroCopyOutputStream;
|
||||
}
|
||||
class FileDescriptor;
|
||||
class GeneratedCodeInfo;
|
||||
|
||||
namespace compiler {
|
||||
class AccessInfoMap;
|
||||
|
||||
class Version;
|
||||
|
||||
// Defined in this file.
|
||||
class CodeGenerator;
|
||||
class GeneratorContext;
|
||||
|
||||
// The abstract interface to a class which generates code implementing a
|
||||
// particular proto file in a particular language. A number of these may
|
||||
// be registered with CommandLineInterface to support various languages.
|
||||
class PROTOC_EXPORT CodeGenerator {
|
||||
public:
|
||||
CodeGenerator() {}
|
||||
CodeGenerator(const CodeGenerator&) = delete;
|
||||
CodeGenerator& operator=(const CodeGenerator&) = delete;
|
||||
virtual ~CodeGenerator();
|
||||
|
||||
// Generates code for the given proto file, generating one or more files in
|
||||
// the given output directory.
|
||||
//
|
||||
// A parameter to be passed to the generator can be specified on the command
|
||||
// line. This is intended to be used to pass generator specific parameters.
|
||||
// It is empty if no parameter was given. ParseGeneratorParameter (below),
|
||||
// can be used to accept multiple parameters within the single parameter
|
||||
// command line flag.
|
||||
//
|
||||
// Returns true if successful. Otherwise, sets *error to a description of
|
||||
// the problem (e.g. "invalid parameter") and returns false.
|
||||
virtual bool Generate(const FileDescriptor* file,
|
||||
const std::string& parameter,
|
||||
GeneratorContext* generator_context,
|
||||
std::string* error) const = 0;
|
||||
|
||||
// Generates code for all given proto files.
|
||||
//
|
||||
// WARNING: The canonical code generator design produces one or two output
|
||||
// files per input .proto file, and we do not wish to encourage alternate
|
||||
// designs.
|
||||
//
|
||||
// A parameter is given as passed on the command line, as in |Generate()|
|
||||
// above.
|
||||
//
|
||||
// Returns true if successful. Otherwise, sets *error to a description of
|
||||
// the problem (e.g. "invalid parameter") and returns false.
|
||||
virtual bool GenerateAll(const std::vector<const FileDescriptor*>& files,
|
||||
const std::string& parameter,
|
||||
GeneratorContext* generator_context,
|
||||
std::string* error) const;
|
||||
|
||||
// This must be kept in sync with plugin.proto. See that file for
|
||||
// documentation on each value.
|
||||
enum Feature {
|
||||
FEATURE_PROTO3_OPTIONAL = 1,
|
||||
};
|
||||
|
||||
// Implement this to indicate what features this code generator supports.
|
||||
//
|
||||
// This must be a bitwise OR of values from the Feature enum above (or zero).
|
||||
virtual uint64_t GetSupportedFeatures() const { return 0; }
|
||||
|
||||
// This is no longer used, but this class is part of the opensource protobuf
|
||||
// library, so it has to remain to keep vtables the same for the current
|
||||
// version of the library. When protobufs does a api breaking change, the
|
||||
// method can be removed.
|
||||
virtual bool HasGenerateAll() const { return true; }
|
||||
};
|
||||
|
||||
// CodeGenerators generate one or more files in a given directory. This
|
||||
// abstract interface represents the directory to which the CodeGenerator is
|
||||
// to write and other information about the context in which the Generator
|
||||
// runs.
|
||||
class PROTOC_EXPORT GeneratorContext {
|
||||
public:
|
||||
GeneratorContext() {
|
||||
}
|
||||
GeneratorContext(const GeneratorContext&) = delete;
|
||||
GeneratorContext& operator=(const GeneratorContext&) = delete;
|
||||
virtual ~GeneratorContext();
|
||||
|
||||
// Opens the given file, truncating it if it exists, and returns a
|
||||
// ZeroCopyOutputStream that writes to the file. The caller takes ownership
|
||||
// of the returned object. This method never fails (a dummy stream will be
|
||||
// returned instead).
|
||||
//
|
||||
// The filename given should be relative to the root of the source tree.
|
||||
// E.g. the C++ generator, when generating code for "foo/bar.proto", will
|
||||
// generate the files "foo/bar.pb.h" and "foo/bar.pb.cc"; note that
|
||||
// "foo/" is included in these filenames. The filename is not allowed to
|
||||
// contain "." or ".." components.
|
||||
virtual io::ZeroCopyOutputStream* Open(const std::string& filename) = 0;
|
||||
|
||||
// Similar to Open() but the output will be appended to the file if exists
|
||||
virtual io::ZeroCopyOutputStream* OpenForAppend(const std::string& filename);
|
||||
|
||||
// Creates a ZeroCopyOutputStream which will insert code into the given file
|
||||
// at the given insertion point. See plugin.proto (plugin.pb.h) for more
|
||||
// information on insertion points. The default implementation
|
||||
// assert-fails -- it exists only for backwards-compatibility.
|
||||
//
|
||||
// WARNING: This feature is currently EXPERIMENTAL and is subject to change.
|
||||
virtual io::ZeroCopyOutputStream* OpenForInsert(
|
||||
const std::string& filename, const std::string& insertion_point);
|
||||
|
||||
// Similar to OpenForInsert, but if `info` is non-empty, will open (or create)
|
||||
// filename.pb.meta and insert info at the appropriate place with the
|
||||
// necessary shifts. The default implementation ignores `info`.
|
||||
//
|
||||
// WARNING: This feature will be REMOVED in the near future.
|
||||
virtual io::ZeroCopyOutputStream* OpenForInsertWithGeneratedCodeInfo(
|
||||
const std::string& filename, const std::string& insertion_point,
|
||||
const google::protobuf::GeneratedCodeInfo& info);
|
||||
|
||||
// Returns a vector of FileDescriptors for all the files being compiled
|
||||
// in this run. Useful for languages, such as Go, that treat files
|
||||
// differently when compiled as a set rather than individually.
|
||||
virtual void ListParsedFiles(std::vector<const FileDescriptor*>* output);
|
||||
|
||||
// Retrieves the version number of the protocol compiler associated with
|
||||
// this GeneratorContext.
|
||||
virtual void GetCompilerVersion(Version* version) const;
|
||||
|
||||
};
|
||||
|
||||
// The type GeneratorContext was once called OutputDirectory. This typedef
|
||||
// provides backward compatibility.
|
||||
typedef GeneratorContext OutputDirectory;
|
||||
|
||||
// Several code generators treat the parameter argument as holding a
|
||||
// list of options separated by commas. This helper function parses
|
||||
// a set of comma-delimited name/value pairs: e.g.,
|
||||
// "foo=bar,baz,moo=corge"
|
||||
// parses to the pairs:
|
||||
// ("foo", "bar"), ("baz", ""), ("moo", "corge")
|
||||
PROTOC_EXPORT void ParseGeneratorParameter(
|
||||
const std::string&, std::vector<std::pair<std::string, std::string> >*);
|
||||
|
||||
// Strips ".proto" or ".protodevel" from the end of a filename.
|
||||
PROTOC_EXPORT std::string StripProto(const std::string& filename);
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__
|
||||
2660
libs/protobuf/src/google/protobuf/compiler/command_line_interface.cc
Normal file
2660
libs/protobuf/src/google/protobuf/compiler/command_line_interface.cc
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,470 @@
|
||||
// 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.
|
||||
//
|
||||
// Implements the Protocol Compiler front-end such that it may be reused by
|
||||
// custom compilers written to support other languages.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "google/protobuf/port.h"
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
class Descriptor; // descriptor.h
|
||||
class DescriptorDatabase; // descriptor_database.h
|
||||
class DescriptorPool; // descriptor.h
|
||||
class FileDescriptor; // descriptor.h
|
||||
class FileDescriptorSet; // descriptor.h
|
||||
class FileDescriptorProto; // descriptor.pb.h
|
||||
template <typename T>
|
||||
class RepeatedPtrField; // repeated_field.h
|
||||
class SimpleDescriptorDatabase; // descriptor_database.h
|
||||
|
||||
namespace compiler {
|
||||
|
||||
class CodeGenerator; // code_generator.h
|
||||
class GeneratorContext; // code_generator.h
|
||||
class DiskSourceTree; // importer.h
|
||||
|
||||
// This class implements the command-line interface to the protocol compiler.
|
||||
// It is designed to make it very easy to create a custom protocol compiler
|
||||
// supporting the languages of your choice. For example, if you wanted to
|
||||
// create a custom protocol compiler binary which includes both the regular
|
||||
// C++ support plus support for your own custom output "Foo", you would
|
||||
// write a class "FooGenerator" which implements the CodeGenerator interface,
|
||||
// then write a main() procedure like this:
|
||||
//
|
||||
// int main(int argc, char* argv[]) {
|
||||
// google::protobuf::compiler::CommandLineInterface cli;
|
||||
//
|
||||
// // Support generation of C++ source and headers.
|
||||
// google::protobuf::compiler::cpp::CppGenerator cpp_generator;
|
||||
// cli.RegisterGenerator("--cpp_out", &cpp_generator,
|
||||
// "Generate C++ source and header.");
|
||||
//
|
||||
// // Support generation of Foo code.
|
||||
// FooGenerator foo_generator;
|
||||
// cli.RegisterGenerator("--foo_out", &foo_generator,
|
||||
// "Generate Foo file.");
|
||||
//
|
||||
// return cli.Run(argc, argv);
|
||||
// }
|
||||
//
|
||||
// The compiler is invoked with syntax like:
|
||||
// protoc --cpp_out=outdir --foo_out=outdir --proto_path=src src/foo.proto
|
||||
//
|
||||
// The .proto file to compile can be specified on the command line using either
|
||||
// its physical file path, or a virtual path relative to a directory specified
|
||||
// in --proto_path. For example, for src/foo.proto, the following two protoc
|
||||
// invocations work the same way:
|
||||
// 1. protoc --proto_path=src src/foo.proto (physical file path)
|
||||
// 2. protoc --proto_path=src foo.proto (virtual path relative to src)
|
||||
//
|
||||
// If a file path can be interpreted both as a physical file path and as a
|
||||
// relative virtual path, the physical file path takes precedence.
|
||||
//
|
||||
// For a full description of the command-line syntax, invoke it with --help.
|
||||
class PROTOC_EXPORT CommandLineInterface {
|
||||
public:
|
||||
static const char* const kPathSeparator;
|
||||
|
||||
CommandLineInterface();
|
||||
CommandLineInterface(const CommandLineInterface&) = delete;
|
||||
CommandLineInterface& operator=(const CommandLineInterface&) = delete;
|
||||
~CommandLineInterface();
|
||||
|
||||
// Register a code generator for a language.
|
||||
//
|
||||
// Parameters:
|
||||
// * flag_name: The command-line flag used to specify an output file of
|
||||
// this type. The name must start with a '-'. If the name is longer
|
||||
// than one letter, it must start with two '-'s.
|
||||
// * generator: The CodeGenerator which will be called to generate files
|
||||
// of this type.
|
||||
// * help_text: Text describing this flag in the --help output.
|
||||
//
|
||||
// Some generators accept extra parameters. You can specify this parameter
|
||||
// on the command-line by placing it before the output directory, separated
|
||||
// by a colon:
|
||||
// protoc --foo_out=enable_bar:outdir
|
||||
// The text before the colon is passed to CodeGenerator::Generate() as the
|
||||
// "parameter".
|
||||
void RegisterGenerator(const std::string& flag_name, CodeGenerator* generator,
|
||||
const std::string& help_text);
|
||||
|
||||
// Register a code generator for a language.
|
||||
// Besides flag_name you can specify another option_flag_name that could be
|
||||
// used to pass extra parameters to the registered code generator.
|
||||
// Suppose you have registered a generator by calling:
|
||||
// command_line_interface.RegisterGenerator("--foo_out", "--foo_opt", ...)
|
||||
// Then you could invoke the compiler with a command like:
|
||||
// protoc --foo_out=enable_bar:outdir --foo_opt=enable_baz
|
||||
// This will pass "enable_bar,enable_baz" as the parameter to the generator.
|
||||
void RegisterGenerator(const std::string& flag_name,
|
||||
const std::string& option_flag_name,
|
||||
CodeGenerator* generator,
|
||||
const std::string& help_text);
|
||||
|
||||
// Enables "plugins". In this mode, if a command-line flag ends with "_out"
|
||||
// but does not match any registered generator, the compiler will attempt to
|
||||
// find a "plugin" to implement the generator. Plugins are just executables.
|
||||
// They should live somewhere in the PATH.
|
||||
//
|
||||
// The compiler determines the executable name to search for by concatenating
|
||||
// exe_name_prefix with the unrecognized flag name, removing "_out". So, for
|
||||
// example, if exe_name_prefix is "protoc-" and you pass the flag --foo_out,
|
||||
// the compiler will try to run the program "protoc-gen-foo".
|
||||
//
|
||||
// The plugin program should implement the following usage:
|
||||
// plugin [--out=OUTDIR] [--parameter=PARAMETER] PROTO_FILES < DESCRIPTORS
|
||||
// --out indicates the output directory (as passed to the --foo_out
|
||||
// parameter); if omitted, the current directory should be used. --parameter
|
||||
// gives the generator parameter, if any was provided (see below). The
|
||||
// PROTO_FILES list the .proto files which were given on the compiler
|
||||
// command-line; these are the files for which the plugin is expected to
|
||||
// generate output code. Finally, DESCRIPTORS is an encoded FileDescriptorSet
|
||||
// (as defined in descriptor.proto). This is piped to the plugin's stdin.
|
||||
// The set will include descriptors for all the files listed in PROTO_FILES as
|
||||
// well as all files that they import. The plugin MUST NOT attempt to read
|
||||
// the PROTO_FILES directly -- it must use the FileDescriptorSet.
|
||||
//
|
||||
// The plugin should generate whatever files are necessary, as code generators
|
||||
// normally do. It should write the names of all files it generates to
|
||||
// stdout. The names should be relative to the output directory, NOT absolute
|
||||
// names or relative to the current directory. If any errors occur, error
|
||||
// messages should be written to stderr. If an error is fatal, the plugin
|
||||
// should exit with a non-zero exit code.
|
||||
//
|
||||
// Plugins can have generator parameters similar to normal built-in
|
||||
// generators. Extra generator parameters can be passed in via a matching
|
||||
// "_opt" parameter. For example:
|
||||
// protoc --plug_out=enable_bar:outdir --plug_opt=enable_baz
|
||||
// This will pass "enable_bar,enable_baz" as the parameter to the plugin.
|
||||
//
|
||||
void AllowPlugins(const std::string& exe_name_prefix);
|
||||
|
||||
// Run the Protocol Compiler with the given command-line parameters.
|
||||
// Returns the error code which should be returned by main().
|
||||
//
|
||||
// It may not be safe to call Run() in a multi-threaded environment because
|
||||
// it calls strerror(). I'm not sure why you'd want to do this anyway.
|
||||
int Run(int argc, const char* const argv[]);
|
||||
|
||||
// DEPRECATED. Calling this method has no effect. Protocol compiler now
|
||||
// always try to find the .proto file relative to the current directory
|
||||
// first and if the file is not found, it will then treat the input path
|
||||
// as a virtual path.
|
||||
void SetInputsAreProtoPathRelative(bool /* enable */) {}
|
||||
|
||||
// Provides some text which will be printed when the --version flag is
|
||||
// used. The version of libprotoc will also be printed on the next line
|
||||
// after this text.
|
||||
void SetVersionInfo(const std::string& text) { version_info_ = text; }
|
||||
|
||||
|
||||
private:
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
class ErrorPrinter;
|
||||
class GeneratorContextImpl;
|
||||
class MemoryOutputStream;
|
||||
typedef std::unordered_map<std::string, std::unique_ptr<GeneratorContextImpl>>
|
||||
GeneratorContextMap;
|
||||
|
||||
// Clear state from previous Run().
|
||||
void Clear();
|
||||
|
||||
// Remaps the proto file so that it is relative to one of the directories
|
||||
// in proto_path_. Returns false if an error occurred.
|
||||
bool MakeProtoProtoPathRelative(DiskSourceTree* source_tree,
|
||||
std::string* proto,
|
||||
DescriptorDatabase* fallback_database);
|
||||
|
||||
// Remaps each file in input_files_ so that it is relative to one of the
|
||||
// directories in proto_path_. Returns false if an error occurred.
|
||||
bool MakeInputsBeProtoPathRelative(DiskSourceTree* source_tree,
|
||||
DescriptorDatabase* fallback_database);
|
||||
|
||||
// Fails if these files use proto3 optional and the code generator doesn't
|
||||
// support it. This is a permanent check.
|
||||
bool EnforceProto3OptionalSupport(
|
||||
const std::string& codegen_name, uint64_t supported_features,
|
||||
const std::vector<const FileDescriptor*>& parsed_files) const;
|
||||
|
||||
|
||||
// Return status for ParseArguments() and InterpretArgument().
|
||||
enum ParseArgumentStatus {
|
||||
PARSE_ARGUMENT_DONE_AND_CONTINUE,
|
||||
PARSE_ARGUMENT_DONE_AND_EXIT,
|
||||
PARSE_ARGUMENT_FAIL
|
||||
};
|
||||
|
||||
// Parse all command-line arguments.
|
||||
ParseArgumentStatus ParseArguments(int argc, const char* const argv[]);
|
||||
|
||||
// Read an argument file and append the file's content to the list of
|
||||
// arguments. Return false if the file cannot be read.
|
||||
bool ExpandArgumentFile(const std::string& file,
|
||||
std::vector<std::string>* arguments);
|
||||
|
||||
// Parses a command-line argument into a name/value pair. Returns
|
||||
// true if the next argument in the argv should be used as the value,
|
||||
// false otherwise.
|
||||
//
|
||||
// Examples:
|
||||
// "-Isrc/protos" ->
|
||||
// name = "-I", value = "src/protos"
|
||||
// "--cpp_out=src/foo.pb2.cc" ->
|
||||
// name = "--cpp_out", value = "src/foo.pb2.cc"
|
||||
// "foo.proto" ->
|
||||
// name = "", value = "foo.proto"
|
||||
bool ParseArgument(const char* arg, std::string* name, std::string* value);
|
||||
|
||||
// Interprets arguments parsed with ParseArgument.
|
||||
ParseArgumentStatus InterpretArgument(const std::string& name,
|
||||
const std::string& value);
|
||||
|
||||
// Print the --help text to stderr.
|
||||
void PrintHelpText();
|
||||
|
||||
// Loads proto_path_ into the provided source_tree.
|
||||
bool InitializeDiskSourceTree(DiskSourceTree* source_tree,
|
||||
DescriptorDatabase* fallback_database);
|
||||
|
||||
// Verify that all the input files exist in the given database.
|
||||
bool VerifyInputFilesInDescriptors(DescriptorDatabase* fallback_database);
|
||||
|
||||
// Parses input_files_ into parsed_files
|
||||
bool ParseInputFiles(DescriptorPool* descriptor_pool,
|
||||
DiskSourceTree* source_tree,
|
||||
std::vector<const FileDescriptor*>* parsed_files);
|
||||
|
||||
// Generate the given output file from the given input.
|
||||
struct OutputDirective; // see below
|
||||
bool GenerateOutput(const std::vector<const FileDescriptor*>& parsed_files,
|
||||
const OutputDirective& output_directive,
|
||||
GeneratorContext* generator_context);
|
||||
bool GeneratePluginOutput(
|
||||
const std::vector<const FileDescriptor*>& parsed_files,
|
||||
const std::string& plugin_name, const std::string& parameter,
|
||||
GeneratorContext* generator_context, std::string* error);
|
||||
|
||||
// Implements --encode and --decode.
|
||||
bool EncodeOrDecode(const DescriptorPool* pool);
|
||||
|
||||
// Implements the --descriptor_set_out option.
|
||||
bool WriteDescriptorSet(
|
||||
const std::vector<const FileDescriptor*>& parsed_files);
|
||||
|
||||
// Implements the --dependency_out option
|
||||
bool GenerateDependencyManifestFile(
|
||||
const std::vector<const FileDescriptor*>& parsed_files,
|
||||
const GeneratorContextMap& output_directories,
|
||||
DiskSourceTree* source_tree);
|
||||
|
||||
// Get all transitive dependencies of the given file (including the file
|
||||
// itself), adding them to the given list of FileDescriptorProtos. The
|
||||
// protos will be ordered such that every file is listed before any file that
|
||||
// depends on it, so that you can call DescriptorPool::BuildFile() on them
|
||||
// in order. Any files in *already_seen will not be added, and each file
|
||||
// added will be inserted into *already_seen. If include_source_code_info is
|
||||
// true then include the source code information in the FileDescriptorProtos.
|
||||
// If include_json_name is true, populate the json_name field of
|
||||
// FieldDescriptorProto for all fields.
|
||||
static void GetTransitiveDependencies(
|
||||
const FileDescriptor* file, bool include_json_name,
|
||||
bool include_source_code_info,
|
||||
std::set<const FileDescriptor*>* already_seen,
|
||||
RepeatedPtrField<FileDescriptorProto>* output);
|
||||
|
||||
// Implements the --print_free_field_numbers. This function prints free field
|
||||
// numbers into stdout for the message and it's nested message types in
|
||||
// post-order, i.e. nested types first. Printed range are left-right
|
||||
// inclusive, i.e. [a, b].
|
||||
//
|
||||
// Groups:
|
||||
// For historical reasons, groups are considered to share the same
|
||||
// field number space with the parent message, thus it will not print free
|
||||
// field numbers for groups. The field numbers used in the groups are
|
||||
// excluded in the free field numbers of the parent message.
|
||||
//
|
||||
// Extension Ranges:
|
||||
// Extension ranges are considered ocuppied field numbers and they will not be
|
||||
// listed as free numbers in the output.
|
||||
void PrintFreeFieldNumbers(const Descriptor* descriptor);
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
// The name of the executable as invoked (i.e. argv[0]).
|
||||
std::string executable_name_;
|
||||
|
||||
// Version info set with SetVersionInfo().
|
||||
std::string version_info_;
|
||||
|
||||
// Registered generators.
|
||||
struct GeneratorInfo {
|
||||
std::string flag_name;
|
||||
std::string option_flag_name;
|
||||
CodeGenerator* generator;
|
||||
std::string help_text;
|
||||
};
|
||||
|
||||
const GeneratorInfo* FindGeneratorByFlag(const std::string& name) const;
|
||||
const GeneratorInfo* FindGeneratorByOption(const std::string& option) const;
|
||||
|
||||
using GeneratorMap = std::map<std::string, GeneratorInfo>;
|
||||
GeneratorMap generators_by_flag_name_;
|
||||
GeneratorMap generators_by_option_name_;
|
||||
// A map from generator names to the parameters specified using the option
|
||||
// flag. For example, if the user invokes the compiler with:
|
||||
// protoc --foo_out=outputdir --foo_opt=enable_bar ...
|
||||
// Then there will be an entry ("--foo_out", "enable_bar") in this map.
|
||||
std::map<std::string, std::string> generator_parameters_;
|
||||
// Similar to generator_parameters_, but stores the parameters for plugins.
|
||||
std::map<std::string, std::string> plugin_parameters_;
|
||||
|
||||
// See AllowPlugins(). If this is empty, plugins aren't allowed.
|
||||
std::string plugin_prefix_;
|
||||
|
||||
// Maps specific plugin names to files. When executing a plugin, this map
|
||||
// is searched first to find the plugin executable. If not found here, the
|
||||
// PATH (or other OS-specific search strategy) is searched.
|
||||
std::map<std::string, std::string> plugins_;
|
||||
|
||||
// Stuff parsed from command line.
|
||||
enum Mode {
|
||||
MODE_COMPILE, // Normal mode: parse .proto files and compile them.
|
||||
MODE_ENCODE, // --encode: read text from stdin, write binary to stdout.
|
||||
MODE_DECODE, // --decode: read binary from stdin, write text to stdout.
|
||||
MODE_PRINT, // Print mode: print info of the given .proto files and exit.
|
||||
};
|
||||
|
||||
Mode mode_ = MODE_COMPILE;
|
||||
|
||||
enum PrintMode {
|
||||
PRINT_NONE, // Not in MODE_PRINT
|
||||
PRINT_FREE_FIELDS, // --print_free_fields
|
||||
};
|
||||
|
||||
PrintMode print_mode_ = PRINT_NONE;
|
||||
|
||||
enum ErrorFormat {
|
||||
ERROR_FORMAT_GCC, // GCC error output format (default).
|
||||
ERROR_FORMAT_MSVS // Visual Studio output (--error_format=msvs).
|
||||
};
|
||||
|
||||
ErrorFormat error_format_ = ERROR_FORMAT_GCC;
|
||||
|
||||
// True if we should treat warnings as errors that fail the compilation.
|
||||
bool fatal_warnings_ = false;
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>
|
||||
proto_path_; // Search path for proto files.
|
||||
std::vector<std::string> input_files_; // Names of the input proto files.
|
||||
|
||||
// Names of proto files which are allowed to be imported. Used by build
|
||||
// systems to enforce depend-on-what-you-import.
|
||||
std::set<std::string> direct_dependencies_;
|
||||
bool direct_dependencies_explicitly_set_ = false;
|
||||
|
||||
// If there's a violation of depend-on-what-you-import, this string will be
|
||||
// presented to the user. "%s" will be replaced with the violating import.
|
||||
std::string direct_dependencies_violation_msg_;
|
||||
|
||||
// output_directives_ lists all the files we are supposed to output and what
|
||||
// generator to use for each.
|
||||
struct OutputDirective {
|
||||
std::string name; // E.g. "--foo_out"
|
||||
CodeGenerator* generator; // NULL for plugins
|
||||
std::string parameter;
|
||||
std::string output_location;
|
||||
};
|
||||
std::vector<OutputDirective> output_directives_;
|
||||
|
||||
// When using --encode or --decode, this names the type we are encoding or
|
||||
// decoding. (Empty string indicates --decode_raw.)
|
||||
std::string codec_type_;
|
||||
|
||||
// If --descriptor_set_in was given, these are filenames containing
|
||||
// parsed FileDescriptorSets to be used for loading protos. Otherwise, empty.
|
||||
std::vector<std::string> descriptor_set_in_names_;
|
||||
|
||||
// If --descriptor_set_out was given, this is the filename to which the
|
||||
// FileDescriptorSet should be written. Otherwise, empty.
|
||||
std::string descriptor_set_out_name_;
|
||||
|
||||
// If --dependency_out was given, this is the path to the file where the
|
||||
// dependency file will be written. Otherwise, empty.
|
||||
std::string dependency_out_name_;
|
||||
|
||||
// True if --include_imports was given, meaning that we should
|
||||
// write all transitive dependencies to the DescriptorSet. Otherwise, only
|
||||
// the .proto files listed on the command-line are added.
|
||||
bool imports_in_descriptor_set_;
|
||||
|
||||
// True if --include_source_info was given, meaning that we should not strip
|
||||
// SourceCodeInfo from the DescriptorSet.
|
||||
bool source_info_in_descriptor_set_ = false;
|
||||
|
||||
// Was the --disallow_services flag used?
|
||||
bool disallow_services_ = false;
|
||||
|
||||
// When using --encode, this will be passed to SetSerializationDeterministic.
|
||||
bool deterministic_output_ = false;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
|
||||
File diff suppressed because it is too large
Load Diff
260
libs/protobuf/src/google/protobuf/compiler/cpp/BUILD.bazel
Normal file
260
libs/protobuf/src/google/protobuf/compiler/cpp/BUILD.bazel
Normal file
@@ -0,0 +1,260 @@
|
||||
################################################################################
|
||||
# Protocol Buffers Compiler - C++ code generator
|
||||
################################################################################
|
||||
|
||||
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_proto_library", "cc_test")
|
||||
load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
|
||||
load("@rules_proto//proto:defs.bzl", "proto_library")
|
||||
load("//build_defs:cpp_opts.bzl", "COPTS")
|
||||
|
||||
cc_library(
|
||||
name = "names",
|
||||
hdrs = ["names.h"],
|
||||
copts = COPTS,
|
||||
include_prefix = "google/protobuf/compiler/cpp",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":names_internal",
|
||||
"//src/google/protobuf/compiler:code_generator",
|
||||
"//src/google/protobuf:protobuf_nowkt",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "names_internal",
|
||||
hdrs = [
|
||||
"helpers.h",
|
||||
"names.h",
|
||||
"options.h",
|
||||
],
|
||||
srcs = [
|
||||
"helpers.cc",
|
||||
],
|
||||
copts = COPTS,
|
||||
include_prefix = "google/protobuf/compiler/cpp",
|
||||
visibility = ["//pkg:__pkg__"],
|
||||
deps = [
|
||||
"//src/google/protobuf/compiler:code_generator",
|
||||
"//src/google/protobuf:protobuf_nowkt",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "cpp",
|
||||
srcs = [
|
||||
"enum.cc",
|
||||
"enum_field.cc",
|
||||
"extension.cc",
|
||||
"field.cc",
|
||||
"file.cc",
|
||||
"generator.cc",
|
||||
"map_field.cc",
|
||||
"message.cc",
|
||||
"message_field.cc",
|
||||
"padding_optimizer.cc",
|
||||
"parse_function_generator.cc",
|
||||
"primitive_field.cc",
|
||||
"service.cc",
|
||||
"string_field.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"enum.h",
|
||||
"enum_field.h",
|
||||
"extension.h",
|
||||
"field.h",
|
||||
"file.h",
|
||||
"generator.h",
|
||||
"map_field.h",
|
||||
"message.h",
|
||||
"message_field.h",
|
||||
"message_layout_helper.h",
|
||||
"padding_optimizer.h",
|
||||
"parse_function_generator.h",
|
||||
"primitive_field.h",
|
||||
"service.h",
|
||||
"string_field.h",
|
||||
],
|
||||
copts = COPTS,
|
||||
include_prefix = "google/protobuf/compiler/cpp",
|
||||
visibility = [
|
||||
"//pkg:__pkg__",
|
||||
"//src/google/protobuf/compiler:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":names_internal",
|
||||
":names",
|
||||
"//src/google/protobuf:protobuf_nowkt",
|
||||
"//src/google/protobuf/compiler:code_generator",
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
"@com_google_absl//absl/container:btree",
|
||||
"@com_google_absl//absl/container:flat_hash_map",
|
||||
"@com_google_absl//absl/container:flat_hash_set",
|
||||
"@com_google_absl//absl/container:layout",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/synchronization",
|
||||
],
|
||||
)
|
||||
|
||||
proto_library(
|
||||
name = "test_bad_identifiers_proto",
|
||||
testonly = 1,
|
||||
srcs = ["test_bad_identifiers.proto"],
|
||||
strip_import_prefix = "/src",
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "test_bad_identifiers_cc_proto",
|
||||
testonly = 1,
|
||||
deps = [":test_bad_identifiers_proto"],
|
||||
)
|
||||
|
||||
proto_library(
|
||||
name = "test_large_enum_value_proto",
|
||||
testonly = 1,
|
||||
srcs = ["test_large_enum_value.proto"],
|
||||
strip_import_prefix = "/src",
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "test_large_enum_value_cc_proto",
|
||||
testonly = 1,
|
||||
deps = [":test_large_enum_value_proto"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "unittest_lib",
|
||||
hdrs = [
|
||||
"unittest.h",
|
||||
"unittest.inc",
|
||||
],
|
||||
strip_include_prefix = "/src",
|
||||
visibility = ["//pkg:__pkg__"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "unittest",
|
||||
srcs = ["unittest.cc"],
|
||||
copts = COPTS,
|
||||
data = [
|
||||
"//:test_proto_srcs",
|
||||
"//src/google/protobuf:testdata",
|
||||
],
|
||||
deps = [
|
||||
":cpp",
|
||||
":test_bad_identifiers_cc_proto",
|
||||
":unittest_lib",
|
||||
"//:protobuf",
|
||||
"//src/google/protobuf:cc_test_protos",
|
||||
"//src/google/protobuf:test_util",
|
||||
"//src/google/protobuf:test_util2",
|
||||
"//src/google/protobuf/compiler:importer",
|
||||
"//src/google/protobuf/io",
|
||||
"//src/google/protobuf/stubs",
|
||||
"//src/google/protobuf/testing",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "bootstrap_unittest",
|
||||
srcs = ["bootstrap_unittest.cc"],
|
||||
data = [
|
||||
"//:well_known_type_protos",
|
||||
"//src/google/protobuf:descriptor_cc_srcs",
|
||||
"//src/google/protobuf:descriptor_proto_srcs",
|
||||
"//src/google/protobuf:testdata",
|
||||
"//src/google/protobuf/compiler:plugin_proto_srcs",
|
||||
],
|
||||
deps = [
|
||||
":cpp",
|
||||
"//:protobuf",
|
||||
"//src/google/protobuf:test_util2",
|
||||
"//src/google/protobuf/compiler:importer",
|
||||
"//src/google/protobuf/io",
|
||||
"//src/google/protobuf/stubs",
|
||||
"//src/google/protobuf/testing",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "message_size_unittest",
|
||||
srcs = ["message_size_unittest.cc"],
|
||||
deps = [
|
||||
"//:protobuf",
|
||||
"//src/google/protobuf:cc_test_protos",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "metadata_test",
|
||||
srcs = ["metadata_test.cc"],
|
||||
deps = [
|
||||
":cpp",
|
||||
"//:protobuf",
|
||||
"//src/google/protobuf/compiler:annotation_test_util",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "move_unittest",
|
||||
srcs = ["move_unittest.cc"],
|
||||
copts = COPTS,
|
||||
deps = [
|
||||
"//:protobuf",
|
||||
"//src/google/protobuf:cc_test_protos",
|
||||
"//src/google/protobuf:test_util",
|
||||
"//src/google/protobuf/stubs:lite",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "plugin_unittest",
|
||||
srcs = ["plugin_unittest.cc"],
|
||||
deps = [
|
||||
":cpp",
|
||||
"//:protobuf",
|
||||
"//src/google/protobuf/compiler:command_line_interface",
|
||||
"//src/google/protobuf/io",
|
||||
"//src/google/protobuf/testing",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
################################################################################
|
||||
# Distribution packaging
|
||||
################################################################################
|
||||
|
||||
pkg_files(
|
||||
name = "dist_files",
|
||||
srcs = glob(["**/*"]),
|
||||
strip_prefix = strip_prefix.from_root(""),
|
||||
visibility = ["//src:__pkg__"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "test_srcs",
|
||||
srcs = glob([
|
||||
"*_test.cc",
|
||||
"*unittest.cc",
|
||||
]),
|
||||
visibility = ["//src/google/protobuf/compiler:__pkg__"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "test_proto_srcs",
|
||||
srcs = [
|
||||
"test_bad_identifiers.proto",
|
||||
"test_large_enum_value.proto",
|
||||
],
|
||||
visibility = ["//src/google/protobuf/compiler:__pkg__"],
|
||||
)
|
||||
@@ -0,0 +1,198 @@
|
||||
// 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.
|
||||
//
|
||||
// This test insures that net/proto2/proto/descriptor.pb.{h,cc} match exactly
|
||||
// what would be generated by the protocol compiler. These files are not
|
||||
// generated automatically at build time because they are compiled into the
|
||||
// protocol compiler itself. So, if they were auto-generated, you'd have a
|
||||
// chicken-and-egg problem.
|
||||
//
|
||||
// If this test fails, run the script
|
||||
// "generate_descriptor_proto.sh" and add
|
||||
// descriptor.pb.{h,cc} to your changelist.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "google/protobuf/testing/file.h"
|
||||
#include "google/protobuf/testing/file.h"
|
||||
#include "google/protobuf/compiler/cpp/generator.h"
|
||||
#include "google/protobuf/compiler/importer.h"
|
||||
#include "google/protobuf/test_util2.h"
|
||||
#include "google/protobuf/io/zero_copy_stream_impl.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/testing/googletest.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/strings/substitute.h"
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
namespace {
|
||||
std::string FindWithDefault(
|
||||
const absl::flat_hash_map<std::string, std::string>& m,
|
||||
const std::string& k, const std::string& v) {
|
||||
auto it = m.find(k);
|
||||
if (it == m.end()) return v;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
class MockErrorCollector : public MultiFileErrorCollector {
|
||||
public:
|
||||
MockErrorCollector() {}
|
||||
~MockErrorCollector() override {}
|
||||
|
||||
std::string text_;
|
||||
|
||||
// implements ErrorCollector ---------------------------------------
|
||||
void AddError(const std::string& filename, int line, int column,
|
||||
const std::string& message) override {
|
||||
absl::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", filename, line, column,
|
||||
message);
|
||||
}
|
||||
};
|
||||
|
||||
class MockGeneratorContext : public GeneratorContext {
|
||||
public:
|
||||
void ExpectFileMatches(const std::string& virtual_filename,
|
||||
const std::string& physical_filename) {
|
||||
auto it = files_.find(virtual_filename);
|
||||
ASSERT_TRUE(it != files_.end())
|
||||
<< "Generator failed to generate file: " << virtual_filename;
|
||||
|
||||
std::string expected_contents = *it->second;
|
||||
std::string actual_contents;
|
||||
GOOGLE_CHECK_OK(
|
||||
File::GetContents(TestUtil::TestSourceDir() + "/" + physical_filename,
|
||||
&actual_contents, true))
|
||||
<< physical_filename;
|
||||
|
||||
#ifdef WRITE_FILES // Define to debug mismatched files.
|
||||
GOOGLE_CHECK_OK(File::SetContents("/tmp/expected.cc", expected_contents,
|
||||
true));
|
||||
GOOGLE_CHECK_OK(
|
||||
File::SetContents("/tmp/actual.cc", actual_contents, true));
|
||||
#endif
|
||||
|
||||
ASSERT_EQ(expected_contents, actual_contents)
|
||||
<< physical_filename
|
||||
<< " needs to be regenerated. Please run "
|
||||
"generate_descriptor_proto.sh. "
|
||||
"Then add this file to your CL.";
|
||||
}
|
||||
|
||||
// implements GeneratorContext --------------------------------------
|
||||
|
||||
io::ZeroCopyOutputStream* Open(const std::string& filename) override {
|
||||
auto& map_slot = files_[filename];
|
||||
map_slot.reset(new std::string);
|
||||
return new io::StringOutputStream(map_slot.get());
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<std::string, std::unique_ptr<std::string>> files_;
|
||||
};
|
||||
|
||||
const char kDescriptorParameter[] = "dllexport_decl=PROTOBUF_EXPORT";
|
||||
const char kPluginParameter[] = "dllexport_decl=PROTOC_EXPORT";
|
||||
|
||||
|
||||
const char* test_protos[][2] = {
|
||||
{"google/protobuf/descriptor", kDescriptorParameter},
|
||||
{"google/protobuf/compiler/plugin", kPluginParameter},
|
||||
};
|
||||
|
||||
TEST(BootstrapTest, GeneratedFilesMatch) {
|
||||
// We need a mapping from the actual file to virtual and actual path
|
||||
// of the data to compare to.
|
||||
absl::flat_hash_map<std::string, std::string> vpath_map;
|
||||
absl::flat_hash_map<std::string, std::string> rpath_map;
|
||||
rpath_map["third_party/protobuf/test_messages_proto2"] =
|
||||
"net/proto2/z_generated_example/test_messages_proto2";
|
||||
rpath_map["third_party/protobuf/test_messages_proto3"] =
|
||||
"net/proto2/z_generated_example/test_messages_proto3";
|
||||
rpath_map["net/proto2/internal/proto2_weak"] =
|
||||
"net/proto2/z_generated_example/proto2_weak";
|
||||
|
||||
DiskSourceTree source_tree;
|
||||
source_tree.MapPath("", TestUtil::TestSourceDir());
|
||||
|
||||
for (auto file_parameter : test_protos) {
|
||||
MockErrorCollector error_collector;
|
||||
Importer importer(&source_tree, &error_collector);
|
||||
const FileDescriptor* file =
|
||||
importer.Import(file_parameter[0] + std::string(".proto"));
|
||||
ASSERT_TRUE(file != nullptr)
|
||||
<< "Can't import file " << file_parameter[0] + std::string(".proto")
|
||||
<< "\n";
|
||||
EXPECT_EQ("", error_collector.text_);
|
||||
CppGenerator generator;
|
||||
MockGeneratorContext context;
|
||||
#ifdef GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE
|
||||
generator.set_opensource_runtime(true);
|
||||
generator.set_runtime_include_base(GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE);
|
||||
#endif
|
||||
std::string error;
|
||||
ASSERT_TRUE(generator.Generate(file, file_parameter[1], &context, &error));
|
||||
|
||||
std::string vpath =
|
||||
FindWithDefault(vpath_map, file_parameter[0], file_parameter[0]);
|
||||
std::string rpath =
|
||||
FindWithDefault(rpath_map, file_parameter[0], file_parameter[0]);
|
||||
context.ExpectFileMatches(vpath + ".pb.cc", rpath + ".pb.cc");
|
||||
context.ExpectFileMatches(vpath + ".pb.h", rpath + ".pb.h");
|
||||
}
|
||||
}
|
||||
|
||||
// test Generate in cpp_generator.cc
|
||||
TEST(BootstrapTest, OptionNotExist) {
|
||||
cpp::CppGenerator generator;
|
||||
DescriptorPool pool;
|
||||
GeneratorContext* generator_context = nullptr;
|
||||
std::string parameter = "aaa";
|
||||
std::string error;
|
||||
ASSERT_FALSE(generator.Generate(
|
||||
pool.FindFileByName("google/protobuf/descriptor.proto"), parameter,
|
||||
generator_context, &error));
|
||||
EXPECT_EQ(error, "Unknown generator option: " + parameter);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
@@ -0,0 +1,36 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_CPP_GENERATOR_H_
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_CPP_GENERATOR_H_
|
||||
|
||||
#include "google/protobuf/compiler/cpp/generator.h"
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_CPP_GENERATOR_H_
|
||||
574
libs/protobuf/src/google/protobuf/compiler/cpp/enum.cc
Normal file
574
libs/protobuf/src/google/protobuf/compiler/cpp/enum.cc
Normal file
@@ -0,0 +1,574 @@
|
||||
// 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/compiler/cpp/enum.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "absl/container/btree_map.h"
|
||||
#include "absl/container/btree_set.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
#include "google/protobuf/compiler/cpp/names.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
namespace {
|
||||
absl::flat_hash_map<std::string, std::string> EnumVars(
|
||||
const EnumDescriptor* enum_, const Options& options,
|
||||
const EnumValueDescriptor* min, const EnumValueDescriptor* max) {
|
||||
auto classname = ClassName(enum_, false);
|
||||
return {
|
||||
{"Enum", enum_->name()},
|
||||
{"Enum_", ResolveKeyword(enum_->name())},
|
||||
{"Msg_Enum", classname},
|
||||
{"::Msg_Enum", QualifiedClassName(enum_, options)},
|
||||
{"Msg_Enum_",
|
||||
enum_->containing_type() == nullptr ? "" : absl::StrCat(classname, "_")},
|
||||
{"kMin", absl::StrCat(min->number())},
|
||||
{"kMax", absl::StrCat(max->number())},
|
||||
};
|
||||
}
|
||||
|
||||
// The ARRAYSIZE constant is the max enum value plus 1. If the max enum value
|
||||
// is kint32max, ARRAYSIZE will overflow. In such cases we should omit the
|
||||
// generation of the ARRAYSIZE constant.
|
||||
bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
|
||||
int32_t max_value = descriptor->value(0)->number();
|
||||
for (int i = 0; i < descriptor->value_count(); i++) {
|
||||
if (descriptor->value(i)->number() > max_value) {
|
||||
max_value = descriptor->value(i)->number();
|
||||
}
|
||||
}
|
||||
return max_value != std::numeric_limits<int32_t>::max();
|
||||
}
|
||||
} // namespace
|
||||
EnumGenerator::ValueLimits EnumGenerator::ValueLimits::FromEnum(
|
||||
const EnumDescriptor* descriptor) {
|
||||
const EnumValueDescriptor* min_desc = descriptor->value(0);
|
||||
const EnumValueDescriptor* max_desc = descriptor->value(0);
|
||||
|
||||
for (int i = 1; i < descriptor->value_count(); ++i) {
|
||||
if (descriptor->value(i)->number() < min_desc->number()) {
|
||||
min_desc = descriptor->value(i);
|
||||
}
|
||||
if (descriptor->value(i)->number() > max_desc->number()) {
|
||||
max_desc = descriptor->value(i);
|
||||
}
|
||||
}
|
||||
|
||||
return EnumGenerator::ValueLimits{min_desc, max_desc};
|
||||
}
|
||||
|
||||
EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
|
||||
const Options& options)
|
||||
: enum_(descriptor),
|
||||
options_(options),
|
||||
generate_array_size_(ShouldGenerateArraySize(descriptor)),
|
||||
has_reflection_(HasDescriptorMethods(enum_->file(), options_)),
|
||||
limits_(ValueLimits::FromEnum(enum_)) {
|
||||
// The conditions here for what is "sparse" are not rigorously
|
||||
// chosen.
|
||||
size_t values_range = static_cast<size_t>(limits_.max->number()) -
|
||||
static_cast<size_t>(limits_.min->number());
|
||||
size_t total_values = static_cast<size_t>(enum_->value_count());
|
||||
should_cache_ = has_reflection_ &&
|
||||
(values_range < 16u || values_range < total_values * 2u);
|
||||
}
|
||||
|
||||
void EnumGenerator::GenerateDefinition(io::Printer* p) {
|
||||
auto v1 = p->WithVars(EnumVars(enum_, options_, limits_.min, limits_.max));
|
||||
|
||||
auto v2 = p->WithVars({
|
||||
{"Msg_Enum_Enum_MIN",
|
||||
absl::StrCat(p->LookupVar("Msg_Enum_"), enum_->name(), "_MIN"), enum_},
|
||||
{"Msg_Enum_Enum_MAX",
|
||||
absl::StrCat(p->LookupVar("Msg_Enum_"), enum_->name(), "_MAX"), enum_},
|
||||
});
|
||||
p->Emit(
|
||||
{
|
||||
{"values",
|
||||
[&] {
|
||||
for (int i = 0; i < enum_->value_count(); ++i) {
|
||||
const auto* value = enum_->value(i);
|
||||
p->Emit(
|
||||
{
|
||||
{
|
||||
"Msg_Enum_VALUE",
|
||||
absl::StrCat(p->LookupVar("Msg_Enum_"),
|
||||
EnumValueName(value)),
|
||||
value,
|
||||
},
|
||||
{"kNumber", Int32ToString(value->number())},
|
||||
{"DEPRECATED", value->options().deprecated()
|
||||
? "PROTOBUF_DEPRECATED_ENUM"
|
||||
: ""},
|
||||
},
|
||||
R"cc(
|
||||
$Msg_Enum_VALUE$$ DEPRECATED$ = $kNumber$,
|
||||
)cc");
|
||||
}
|
||||
}},
|
||||
// Only emit annotations for the $Msg_Enum$ used in the `enum`
|
||||
// definition.
|
||||
{"Msg_Enum_annotated", p->LookupVar("Msg_Enum"), enum_},
|
||||
{"open_enum_sentinels",
|
||||
[&] {
|
||||
if (enum_->is_closed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For open enum semantics: generate min and max sentinel values
|
||||
// equal to INT32_MIN and INT32_MAX
|
||||
p->Emit({{"Msg_Enum_Msg_Enum_",
|
||||
absl::StrCat(p->LookupVar("Msg_Enum"), "_",
|
||||
p->LookupVar("Msg_Enum_"))}},
|
||||
R"cc(
|
||||
$Msg_Enum_Msg_Enum_$INT_MIN_SENTINEL_DO_NOT_USE_ =
|
||||
std::numeric_limits<int32_t>::min(),
|
||||
$Msg_Enum_Msg_Enum_$INT_MAX_SENTINEL_DO_NOT_USE_ =
|
||||
std::numeric_limits<int32_t>::max(),
|
||||
)cc");
|
||||
}},
|
||||
},
|
||||
R"cc(
|
||||
enum $Msg_Enum_annotated$ : int {
|
||||
$values$,
|
||||
$open_enum_sentinels$,
|
||||
};
|
||||
|
||||
$dllexport_decl $bool $Msg_Enum$_IsValid(int value);
|
||||
constexpr $Msg_Enum$ $Msg_Enum_Enum_MIN$ = static_cast<$Msg_Enum$>($kMin$);
|
||||
constexpr $Msg_Enum$ $Msg_Enum_Enum_MAX$ = static_cast<$Msg_Enum$>($kMax$);
|
||||
)cc");
|
||||
|
||||
if (generate_array_size_) {
|
||||
p->Emit(
|
||||
{{"Msg_Enum_Enum_ARRAYSIZE",
|
||||
absl::StrCat(p->LookupVar("Msg_Enum_"), enum_->name(), "_ARRAYSIZE"),
|
||||
enum_}},
|
||||
R"cc(
|
||||
constexpr int $Msg_Enum_Enum_ARRAYSIZE$ = $kMax$ + 1;
|
||||
)cc");
|
||||
}
|
||||
|
||||
if (has_reflection_) {
|
||||
p->Emit(R"cc(
|
||||
$dllexport_decl $const ::$proto_ns$::EnumDescriptor*
|
||||
$Msg_Enum$_descriptor();
|
||||
)cc");
|
||||
} else {
|
||||
p->Emit(R"cc(
|
||||
const std::string& $Msg_Enum$_Name($Msg_Enum$ value);
|
||||
)cc");
|
||||
}
|
||||
|
||||
// There are three possible implementations of $Enum$_Name() and
|
||||
// $Msg_Enum$_Parse(), depending on whether we are using a dense enum name
|
||||
// cache or not, and whether or not we have reflection. Very little code is
|
||||
// shared between the three, so it is split into three Emit() calls.
|
||||
|
||||
// Can't use WithVars here, since callbacks can only be passed to Emit()
|
||||
// directly. Because this includes $Enum$, it must be a callback.
|
||||
auto write_assert = [&] {
|
||||
p->Emit(R"cc(
|
||||
static_assert(std::is_same<T, $Msg_Enum$>::value ||
|
||||
std::is_integral<T>::value,
|
||||
"Incorrect type passed to $Enum$_Name().");
|
||||
)cc");
|
||||
};
|
||||
|
||||
if (should_cache_ || !has_reflection_) {
|
||||
p->Emit({{"static_assert", write_assert}}, R"cc(
|
||||
template <typename T>
|
||||
const std::string& $Msg_Enum$_Name(T value) {
|
||||
$static_assert$;
|
||||
return $Msg_Enum$_Name(static_cast<$Msg_Enum$>(value));
|
||||
}
|
||||
)cc");
|
||||
if (should_cache_) {
|
||||
// Using the NameOfEnum routine can be slow, so we create a small
|
||||
// cache of pointers to the std::string objects that reflection
|
||||
// stores internally. This cache is a simple contiguous array of
|
||||
// pointers, so if the enum values are sparse, it's not worth it.
|
||||
p->Emit(R"cc(
|
||||
template <>
|
||||
inline const std::string& $Msg_Enum$_Name($Msg_Enum$ value) {
|
||||
return ::$proto_ns$::internal::NameOfDenseEnum<$Msg_Enum$_descriptor,
|
||||
$kMin$, $kMax$>(
|
||||
static_cast<int>(value));
|
||||
}
|
||||
)cc");
|
||||
} else {
|
||||
p->Emit(R"cc(
|
||||
const std::string& $Msg_Enum$_Name($Msg_Enum$ value);
|
||||
)cc");
|
||||
}
|
||||
} else {
|
||||
p->Emit({{"static_assert", write_assert}}, R"cc(
|
||||
template <typename T>
|
||||
const std::string& $Msg_Enum$_Name(T value) {
|
||||
$static_assert$;
|
||||
return ::$proto_ns$::internal::NameOfEnum($Msg_Enum$_descriptor(), value);
|
||||
}
|
||||
)cc");
|
||||
}
|
||||
|
||||
if (has_reflection_) {
|
||||
p->Emit(R"cc(
|
||||
inline bool $Msg_Enum$_Parse(absl::string_view name, $Msg_Enum$* value) {
|
||||
return ::$proto_ns$::internal::ParseNamedEnum<$Msg_Enum$>(
|
||||
$Msg_Enum$_descriptor(), name, value);
|
||||
}
|
||||
)cc");
|
||||
} else {
|
||||
p->Emit(R"cc(
|
||||
bool $Msg_Enum$_Parse(absl::string_view name, $Msg_Enum$* value);
|
||||
)cc");
|
||||
}
|
||||
}
|
||||
|
||||
void EnumGenerator::GenerateGetEnumDescriptorSpecializations(io::Printer* p) {
|
||||
auto v = p->WithVars(EnumVars(enum_, options_, limits_.min, limits_.max));
|
||||
|
||||
p->Emit(R"cc(
|
||||
template <>
|
||||
struct is_proto_enum<$::Msg_Enum$> : std::true_type {};
|
||||
)cc");
|
||||
if (!has_reflection_) {
|
||||
return;
|
||||
}
|
||||
p->Emit(R"cc(
|
||||
template <>
|
||||
inline const EnumDescriptor* GetEnumDescriptor<$::Msg_Enum$>() {
|
||||
return $::Msg_Enum$_descriptor();
|
||||
}
|
||||
)cc");
|
||||
}
|
||||
|
||||
void EnumGenerator::GenerateSymbolImports(io::Printer* p) const {
|
||||
auto v = p->WithVars(EnumVars(enum_, options_, limits_.min, limits_.max));
|
||||
|
||||
p->Emit(R"cc(
|
||||
using $Enum_$ = $Msg_Enum$;
|
||||
)cc");
|
||||
|
||||
for (int j = 0; j < enum_->value_count(); ++j) {
|
||||
const auto* value = enum_->value(j);
|
||||
p->Emit(
|
||||
{
|
||||
{"VALUE", EnumValueName(enum_->value(j)), value},
|
||||
{"DEPRECATED",
|
||||
value->options().deprecated() ? "PROTOBUF_DEPRECATED_ENUM" : ""},
|
||||
},
|
||||
R"cc(
|
||||
$DEPRECATED $static constexpr $Enum_$ $VALUE$ = $Msg_Enum$_$VALUE$;
|
||||
)cc");
|
||||
}
|
||||
|
||||
p->Emit(
|
||||
{
|
||||
{"Enum_MIN", absl::StrCat(enum_->name(), "_MIN"), enum_},
|
||||
{"Enum_MAX", absl::StrCat(enum_->name(), "_MAX"), enum_},
|
||||
},
|
||||
R"cc(
|
||||
static inline bool $Enum$_IsValid(int value) {
|
||||
return $Msg_Enum$_IsValid(value);
|
||||
}
|
||||
static constexpr $Enum_$ $Enum_MIN$ = $Msg_Enum$_$Enum$_MIN;
|
||||
static constexpr $Enum_$ $Enum_MAX$ = $Msg_Enum$_$Enum$_MAX;
|
||||
)cc");
|
||||
|
||||
if (generate_array_size_) {
|
||||
p->Emit(
|
||||
{{"Enum_ARRAYSIZE", absl::StrCat(enum_->name(), "_ARRAYSIZE"), enum_}},
|
||||
R"cc(
|
||||
static constexpr int $Enum_ARRAYSIZE$ = $Msg_Enum$_$Enum$_ARRAYSIZE;
|
||||
)cc");
|
||||
}
|
||||
|
||||
if (has_reflection_) {
|
||||
p->Emit(R"cc(
|
||||
static inline const ::$proto_ns$::EnumDescriptor* $Enum$_descriptor() {
|
||||
return $Msg_Enum$_descriptor();
|
||||
}
|
||||
)cc");
|
||||
}
|
||||
|
||||
p->Emit(R"cc(
|
||||
template <typename T>
|
||||
static inline const std::string& $Enum$_Name(T value) {
|
||||
return $Msg_Enum$_Name(value);
|
||||
}
|
||||
static inline bool $Enum$_Parse(absl::string_view name, $Enum_$* value) {
|
||||
return $Msg_Enum$_Parse(name, value);
|
||||
}
|
||||
)cc");
|
||||
}
|
||||
|
||||
void EnumGenerator::GenerateMethods(int idx, io::Printer* p) {
|
||||
auto v = p->WithVars(EnumVars(enum_, options_, limits_.min, limits_.max));
|
||||
|
||||
if (has_reflection_) {
|
||||
p->Emit({{"idx", idx}}, R"cc(
|
||||
const ::$proto_ns$::EnumDescriptor* $Msg_Enum$_descriptor() {
|
||||
::$proto_ns$::internal::AssignDescriptors(&$desc_table$);
|
||||
return $file_level_enum_descriptors$[$idx$];
|
||||
}
|
||||
)cc");
|
||||
}
|
||||
|
||||
p->Emit({{"cases",
|
||||
[&] {
|
||||
// Multiple values may have the same number. Make sure we only
|
||||
// cover each number once by first constructing a set containing
|
||||
// all valid numbers, then printing a case statement for each
|
||||
// element.
|
||||
|
||||
std::vector<int> numbers;
|
||||
numbers.reserve(enum_->value_count());
|
||||
for (int i = 0; i < enum_->value_count(); ++i) {
|
||||
numbers.push_back(enum_->value(i)->number());
|
||||
}
|
||||
// Sort and deduplicate `numbers`.
|
||||
absl::c_sort(numbers);
|
||||
numbers.erase(std::unique(numbers.begin(), numbers.end()),
|
||||
numbers.end());
|
||||
|
||||
for (int n : numbers) {
|
||||
p->Emit({{"n", n}}, R"cc(
|
||||
case $n$:
|
||||
)cc");
|
||||
}
|
||||
}}},
|
||||
R"(
|
||||
bool $Msg_Enum$_IsValid(int value) {
|
||||
switch (value) {
|
||||
$cases$;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
)");
|
||||
|
||||
if (!has_reflection_) {
|
||||
// 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.
|
||||
|
||||
absl::btree_map<std::string, int> name_to_number;
|
||||
absl::flat_hash_map<int, std::string> number_to_canonical_name;
|
||||
for (int i = 0; i < enum_->value_count(); ++i) {
|
||||
const auto* value = enum_->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());
|
||||
}
|
||||
|
||||
// Build the offset table for the strings table.
|
||||
struct Offset {
|
||||
int number;
|
||||
size_t index, byte_offset, len;
|
||||
};
|
||||
std::vector<Offset> offsets;
|
||||
size_t index = 0;
|
||||
size_t offset = 0;
|
||||
for (const auto& e : name_to_number) {
|
||||
offsets.push_back(Offset{e.second, index, offset, e.first.size()});
|
||||
++index;
|
||||
offset += e.first.size();
|
||||
}
|
||||
absl::c_sort(offsets, [](const auto& a, const auto& b) {
|
||||
return a.byte_offset < b.byte_offset;
|
||||
});
|
||||
|
||||
std::vector<Offset> offsets_by_number = offsets;
|
||||
absl::c_sort(offsets_by_number, [](const auto& a, const auto& b) {
|
||||
return a.number < b.number;
|
||||
});
|
||||
|
||||
offsets_by_number.erase(
|
||||
std::unique(
|
||||
offsets_by_number.begin(), offsets_by_number.end(),
|
||||
[](const auto& a, const auto& b) { return a.number == b.number; }),
|
||||
offsets_by_number.end());
|
||||
|
||||
p->Emit(
|
||||
{
|
||||
{"num_unique", number_to_canonical_name.size()},
|
||||
{"num_declared", enum_->value_count()},
|
||||
{"names",
|
||||
// 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.
|
||||
[&] {
|
||||
for (const auto& e : name_to_number) {
|
||||
p->Emit({{"name", e.first}}, R"cc(
|
||||
"$name$"
|
||||
)cc");
|
||||
}
|
||||
}},
|
||||
{"entries",
|
||||
[&] {
|
||||
for (const auto& offset : offsets) {
|
||||
p->Emit({{"number", offset.number},
|
||||
{"offset", offset.byte_offset},
|
||||
{"len", offset.len}},
|
||||
R"cc(
|
||||
{{&$Msg_Enum$_names[$offset$], $len$}, $number$},
|
||||
)cc");
|
||||
}
|
||||
}},
|
||||
{"entries_by_number",
|
||||
[&] {
|
||||
for (const auto& offset : offsets_by_number) {
|
||||
p->Emit({{"number", offset.number},
|
||||
{"index", offset.index},
|
||||
{"name", number_to_canonical_name[offset.number]}},
|
||||
R"cc(
|
||||
$index$, // $number$ -> $name$
|
||||
)cc");
|
||||
}
|
||||
}},
|
||||
},
|
||||
R"cc(
|
||||
static ::$proto_ns$::internal::ExplicitlyConstructed<std::string>
|
||||
$Msg_Enum$_strings[$num_unique$] = {};
|
||||
|
||||
static const char $Msg_Enum$_names[] = {
|
||||
$names$,
|
||||
};
|
||||
|
||||
static const ::$proto_ns$::internal::EnumEntry $Msg_Enum$_entries[] =
|
||||
{
|
||||
$entries$,
|
||||
};
|
||||
|
||||
static const int $Msg_Enum$_entries_by_number[] = {
|
||||
$entries_by_number$,
|
||||
};
|
||||
|
||||
const std::string& $Msg_Enum$_Name($Msg_Enum$ value) {
|
||||
static const bool kDummy =
|
||||
::$proto_ns$::internal::InitializeEnumStrings(
|
||||
$Msg_Enum$_entries, $Msg_Enum$_entries_by_number,
|
||||
$num_unique$, $Msg_Enum$_strings);
|
||||
(void)kDummy;
|
||||
|
||||
int idx = ::$proto_ns$::internal::LookUpEnumName(
|
||||
$Msg_Enum$_entries, $Msg_Enum$_entries_by_number, $num_unique$,
|
||||
value);
|
||||
return idx == -1 ? ::$proto_ns$::internal::GetEmptyString()
|
||||
: $Msg_Enum$_strings[idx].get();
|
||||
}
|
||||
|
||||
bool $Msg_Enum$_Parse(absl::string_view name, $Msg_Enum$* value) {
|
||||
int int_value;
|
||||
bool success = ::$proto_ns$::internal::LookUpEnumValue(
|
||||
$Msg_Enum$_entries, $num_declared$, name, &int_value);
|
||||
if (success) {
|
||||
*value = static_cast<$Msg_Enum$>(int_value);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
)cc");
|
||||
}
|
||||
|
||||
if (enum_->containing_type() != nullptr) {
|
||||
// Before C++17, we must define the static constants which were
|
||||
// declared in the header, to give the linker a place to put them.
|
||||
// But MSVC++ pre-2015 and post-2017 (version 15.5+) insists that we not.
|
||||
p->Emit(
|
||||
{
|
||||
{"Msg_", ClassName(enum_->containing_type(), false)},
|
||||
{"constexpr_storage",
|
||||
[&] {
|
||||
for (int i = 0; i < enum_->value_count(); i++) {
|
||||
p->Emit({{"VALUE", EnumValueName(enum_->value(i))}},
|
||||
R"cc(
|
||||
constexpr $Msg_Enum$ $Msg_$::$VALUE$;
|
||||
)cc");
|
||||
}
|
||||
}},
|
||||
{"array_size",
|
||||
[&] {
|
||||
if (generate_array_size_) {
|
||||
p->Emit(R"cc(
|
||||
constexpr int $Msg_$::$Enum$_ARRAYSIZE;
|
||||
)cc");
|
||||
}
|
||||
}},
|
||||
},
|
||||
R"(
|
||||
#if (__cplusplus < 201703) && \
|
||||
(!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
|
||||
|
||||
$constexpr_storage$;
|
||||
constexpr $Msg_Enum$ $Msg_$::$Enum$_MIN;
|
||||
constexpr $Msg_Enum$ $Msg_$::$Enum$_MAX;
|
||||
$array_size$;
|
||||
|
||||
#endif // (__cplusplus < 201703) &&
|
||||
// (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
|
||||
)");
|
||||
}
|
||||
}
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
105
libs/protobuf/src/google/protobuf/compiler/cpp/enum.h
Normal file
105
libs/protobuf/src/google/protobuf/compiler/cpp/enum.h
Normal file
@@ -0,0 +1,105 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/compiler/cpp/options.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
class EnumGenerator {
|
||||
public:
|
||||
EnumGenerator(const EnumDescriptor* descriptor, const Options& options);
|
||||
|
||||
EnumGenerator(const EnumGenerator&) = delete;
|
||||
EnumGenerator& operator=(const EnumGenerator&) = delete;
|
||||
|
||||
~EnumGenerator() = default;
|
||||
|
||||
// Generate header code defining the enum. This code should be placed
|
||||
// within the enum's package namespace, but NOT within any class, even for
|
||||
// nested enums.
|
||||
void GenerateDefinition(io::Printer* p);
|
||||
|
||||
// Generate specialization of GetEnumDescriptor<MyEnum>().
|
||||
// Precondition: in ::google::protobuf namespace.
|
||||
void GenerateGetEnumDescriptorSpecializations(io::Printer* p);
|
||||
|
||||
// For enums nested within a message, generate code to import all the enum's
|
||||
// symbols (e.g. the enum type name, all its values, etc.) into the class's
|
||||
// namespace. This should be placed inside the class definition in the
|
||||
// header.
|
||||
void GenerateSymbolImports(io::Printer* p) const;
|
||||
|
||||
// Source file stuff.
|
||||
|
||||
// Generate non-inline methods related to the enum, such as IsValidValue().
|
||||
// Goes in the .cc file. EnumDescriptors are stored in an array, idx is
|
||||
// the index in this array that corresponds with this enum.
|
||||
void GenerateMethods(int idx, io::Printer* p);
|
||||
|
||||
private:
|
||||
friend class FileGenerator;
|
||||
|
||||
struct ValueLimits {
|
||||
const EnumValueDescriptor* min;
|
||||
const EnumValueDescriptor* max;
|
||||
|
||||
static ValueLimits FromEnum(const EnumDescriptor* descriptor);
|
||||
};
|
||||
|
||||
const EnumDescriptor* enum_;
|
||||
Options options_;
|
||||
|
||||
bool generate_array_size_;
|
||||
bool should_cache_;
|
||||
bool has_reflection_;
|
||||
ValueLimits limits_;
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
|
||||
451
libs/protobuf/src/google/protobuf/compiler/cpp/enum_field.cc
Normal file
451
libs/protobuf/src/google/protobuf/compiler/cpp/enum_field.cc
Normal file
@@ -0,0 +1,451 @@
|
||||
// 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/compiler/cpp/enum_field.h"
|
||||
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "google/protobuf/wire_format.h"
|
||||
#include "google/protobuf/compiler/cpp/field.h"
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
namespace {
|
||||
|
||||
void SetEnumVariables(const FieldDescriptor* descriptor,
|
||||
std::map<std::string, std::string>* variables,
|
||||
const Options& options) {
|
||||
SetCommonFieldVariables(descriptor, variables, options);
|
||||
const EnumValueDescriptor* default_value = descriptor->default_value_enum();
|
||||
(*variables)["type"] = QualifiedClassName(descriptor->enum_type(), options);
|
||||
(*variables)["default"] = Int32ToString(default_value->number());
|
||||
(*variables)["full_name"] = descriptor->full_name();
|
||||
(*variables)["cached_byte_size_name"] = MakeVarintCachedSizeName(descriptor);
|
||||
bool cold = ShouldSplit(descriptor, options);
|
||||
(*variables)["cached_byte_size_field"] =
|
||||
MakeVarintCachedSizeFieldName(descriptor, cold);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options)
|
||||
: FieldGenerator(descriptor, options) {
|
||||
SetEnumVariables(descriptor, &variables_, options);
|
||||
}
|
||||
|
||||
EnumFieldGenerator::~EnumFieldGenerator() {}
|
||||
|
||||
void EnumFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("int $name$_;\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::GenerateAccessorDeclarations(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"$deprecated_attr$$type$ ${1$$name$$}$() const;\n"
|
||||
"$deprecated_attr$void ${1$set_$name$$}$($type$ value);\n"
|
||||
"private:\n"
|
||||
"$type$ ${1$_internal_$name$$}$() const;\n"
|
||||
"void ${1$_internal_set_$name$$}$($type$ value);\n"
|
||||
"public:\n",
|
||||
descriptor_);
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"inline $type$ $classname$::_internal_$name$() const {\n"
|
||||
" return static_cast< $type$ >($field$);\n"
|
||||
"}\n"
|
||||
"inline $type$ $classname$::$name$() const {\n"
|
||||
"$annotate_get$"
|
||||
" // @@protoc_insertion_point(field_get:$full_name$)\n"
|
||||
" return _internal_$name$();\n"
|
||||
"}\n"
|
||||
"inline void $classname$::_internal_set_$name$($type$ value) {\n");
|
||||
if (!internal::cpp::HasPreservingUnknownEnumSemantics(descriptor_)) {
|
||||
format(" assert($type$_IsValid(value));\n");
|
||||
}
|
||||
format(
|
||||
" $set_hasbit$\n"
|
||||
" $field$ = value;\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$($type$ value) {\n"
|
||||
"$maybe_prepare_split_message$"
|
||||
" _internal_set_$name$(value);\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set:$full_name$)\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$ = $default$;\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("_this->_internal_set_$name$(from._internal_$name$());\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("swap($field$, other->$field$);\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::GenerateCopyConstructorCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("_this->$field$ = from.$field$;\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"target = stream->EnsureSpace(target);\n"
|
||||
"target = ::_pbi::WireFormatLite::WriteEnumToArray(\n"
|
||||
" $number$, this->_internal_$name$(), target);\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::GenerateByteSize(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"total_size += $tag_size$ +\n"
|
||||
" ::_pbi::WireFormatLite::EnumSize(this->_internal_$name$());\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::GenerateConstexprAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("/*decltype($field$)*/$default$");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::GenerateAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("decltype(Impl_::Split::$name$_){$default$}");
|
||||
return;
|
||||
}
|
||||
format("decltype($field$){$default$}");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::GenerateCopyAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("decltype($field$){}");
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
EnumOneofFieldGenerator::EnumOneofFieldGenerator(
|
||||
const FieldDescriptor* descriptor, const Options& options)
|
||||
: EnumFieldGenerator(descriptor, options) {
|
||||
SetCommonOneofFieldVariables(descriptor, &variables_);
|
||||
}
|
||||
|
||||
EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {}
|
||||
|
||||
void EnumOneofFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"inline $type$ $classname$::_internal_$name$() const {\n"
|
||||
" if (_internal_has_$name$()) {\n"
|
||||
" return static_cast< $type$ >($field$);\n"
|
||||
" }\n"
|
||||
" return static_cast< $type$ >($default$);\n"
|
||||
"}\n"
|
||||
"inline $type$ $classname$::$name$() const {\n"
|
||||
"$annotate_get$"
|
||||
" // @@protoc_insertion_point(field_get:$full_name$)\n"
|
||||
" return _internal_$name$();\n"
|
||||
"}\n"
|
||||
"inline void $classname$::_internal_set_$name$($type$ value) {\n");
|
||||
if (!internal::cpp::HasPreservingUnknownEnumSemantics(descriptor_)) {
|
||||
format(" assert($type$_IsValid(value));\n");
|
||||
}
|
||||
format(
|
||||
" if (!_internal_has_$name$()) {\n"
|
||||
" clear_$oneof_name$();\n"
|
||||
" set_has_$name$();\n"
|
||||
" }\n"
|
||||
" $field$ = value;\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$($type$ value) {\n"
|
||||
" _internal_set_$name$(value);\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set:$full_name$)\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void EnumOneofFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$ = $default$;\n");
|
||||
}
|
||||
|
||||
void EnumOneofFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
|
||||
// Don't print any swapping code. Swapping the union will swap this field.
|
||||
}
|
||||
|
||||
void EnumOneofFieldGenerator::GenerateConstructorCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$ns$::_$classname$_default_instance_.$field$ = $default$;\n");
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
|
||||
const FieldDescriptor* descriptor, const Options& options)
|
||||
: FieldGenerator(descriptor, options) {
|
||||
SetEnumVariables(descriptor, &variables_, options);
|
||||
}
|
||||
|
||||
RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
|
||||
|
||||
void RepeatedEnumFieldGenerator::GeneratePrivateMembers(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("::$proto_ns$::RepeatedField<int> $name$_;\n");
|
||||
if (descriptor_->is_packed() &&
|
||||
HasGeneratedMethods(descriptor_->file(), options_)) {
|
||||
format(
|
||||
"mutable ::$proto_ns$::internal::CachedSize "
|
||||
"$cached_byte_size_name$;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::GenerateAccessorDeclarations(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"private:\n"
|
||||
"$type$ ${1$_internal_$name$$}$(int index) const;\n"
|
||||
"void ${1$_internal_add_$name$$}$($type$ value);\n"
|
||||
"::$proto_ns$::RepeatedField<int>* "
|
||||
"${1$_internal_mutable_$name$$}$();\n"
|
||||
"public:\n"
|
||||
"$deprecated_attr$$type$ ${1$$name$$}$(int index) const;\n"
|
||||
"$deprecated_attr$void ${1$set_$name$$}$(int index, $type$ value);\n"
|
||||
"$deprecated_attr$void ${1$add_$name$$}$($type$ value);\n"
|
||||
"$deprecated_attr$const ::$proto_ns$::RepeatedField<int>& "
|
||||
"${1$$name$$}$() const;\n"
|
||||
"$deprecated_attr$::$proto_ns$::RepeatedField<int>* "
|
||||
"${1$mutable_$name$$}$();\n",
|
||||
descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"inline $type$ $classname$::_internal_$name$(int index) const {\n"
|
||||
" return static_cast< $type$ >($field$.Get(index));\n"
|
||||
"}\n"
|
||||
"inline $type$ $classname$::$name$(int index) const {\n"
|
||||
"$annotate_get$"
|
||||
" // @@protoc_insertion_point(field_get:$full_name$)\n"
|
||||
" return _internal_$name$(index);\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$(int index, $type$ value) {\n");
|
||||
if (!internal::cpp::HasPreservingUnknownEnumSemantics(descriptor_)) {
|
||||
format(" assert($type$_IsValid(value));\n");
|
||||
}
|
||||
format(
|
||||
" $field$.Set(index, value);\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set:$full_name$)\n"
|
||||
"}\n"
|
||||
"inline void $classname$::_internal_add_$name$($type$ value) {\n");
|
||||
if (!internal::cpp::HasPreservingUnknownEnumSemantics(descriptor_)) {
|
||||
format(" assert($type$_IsValid(value));\n");
|
||||
}
|
||||
format(
|
||||
" $field$.Add(value);\n"
|
||||
"}\n"
|
||||
"inline void $classname$::add_$name$($type$ value) {\n"
|
||||
" _internal_add_$name$(value);\n"
|
||||
"$annotate_add$"
|
||||
" // @@protoc_insertion_point(field_add:$full_name$)\n"
|
||||
"}\n"
|
||||
"inline const ::$proto_ns$::RepeatedField<int>&\n"
|
||||
"$classname$::$name$() const {\n"
|
||||
"$annotate_list$"
|
||||
" // @@protoc_insertion_point(field_list:$full_name$)\n"
|
||||
" return $field$;\n"
|
||||
"}\n"
|
||||
"inline ::$proto_ns$::RepeatedField<int>*\n"
|
||||
"$classname$::_internal_mutable_$name$() {\n"
|
||||
" return &$field$;\n"
|
||||
"}\n"
|
||||
"inline ::$proto_ns$::RepeatedField<int>*\n"
|
||||
"$classname$::mutable_$name$() {\n"
|
||||
"$annotate_mutable_list$"
|
||||
" // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
|
||||
" return _internal_mutable_$name$();\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::GenerateClearingCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$.Clear();\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::GenerateMergingCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("_this->$field$.MergeFrom(from.$field$);\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::GenerateSwappingCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$.InternalSwap(&other->$field$);\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::GenerateConstructorCode(
|
||||
io::Printer* printer) const {
|
||||
// Not needed for repeated fields.
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::GenerateDestructorCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$.~RepeatedField();\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (descriptor_->is_packed()) {
|
||||
// Write the tag and the size.
|
||||
format(
|
||||
"{\n"
|
||||
" int byte_size = "
|
||||
"$cached_byte_size_field$.Get();\n"
|
||||
" if (byte_size > 0) {\n"
|
||||
" target = stream->WriteEnumPacked(\n"
|
||||
" $number$, $field$, byte_size, target);\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
} else {
|
||||
format(
|
||||
"for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n"
|
||||
" target = stream->EnsureSpace(target);\n"
|
||||
" target = ::_pbi::WireFormatLite::WriteEnumToArray(\n"
|
||||
" $number$, this->_internal_$name$(i), target);\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::GenerateByteSize(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"{\n"
|
||||
" size_t data_size = 0;\n"
|
||||
" unsigned int count = static_cast<unsigned "
|
||||
"int>(this->_internal_$name$_size());");
|
||||
format.Indent();
|
||||
format(
|
||||
"for (unsigned int i = 0; i < count; i++) {\n"
|
||||
" data_size += ::_pbi::WireFormatLite::EnumSize(\n"
|
||||
" this->_internal_$name$(static_cast<int>(i)));\n"
|
||||
"}\n");
|
||||
|
||||
if (descriptor_->is_packed()) {
|
||||
format(
|
||||
"if (data_size > 0) {\n"
|
||||
" total_size += $tag_size$ +\n"
|
||||
" "
|
||||
"::_pbi::WireFormatLite::Int32Size(static_cast<$int32$>(data_size));\n"
|
||||
"}\n"
|
||||
"int cached_size = ::_pbi::ToCachedSize(data_size);\n"
|
||||
"$cached_byte_size_field$.Set(cached_size);\n"
|
||||
"total_size += data_size;\n");
|
||||
} else {
|
||||
format("total_size += ($tag_size$UL * count) + data_size;\n");
|
||||
}
|
||||
format.Outdent();
|
||||
format("}\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::GenerateConstexprAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("/*decltype($field$)*/{}");
|
||||
if (descriptor_->is_packed() &&
|
||||
HasGeneratedMethods(descriptor_->file(), options_)) {
|
||||
format("\n, /*decltype($cached_byte_size_field$)*/{0}");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::GenerateAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("decltype($field$){arena}");
|
||||
if (descriptor_->is_packed() &&
|
||||
HasGeneratedMethods(descriptor_->file(), options_)) {
|
||||
// std::atomic has no copy constructor, which prevents explicit aggregate
|
||||
// initialization pre-C++17.
|
||||
format("\n, /*decltype($cached_byte_size_field$)*/{0}");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::GenerateCopyAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("decltype($field$){from.$field$}");
|
||||
if (descriptor_->is_packed() &&
|
||||
HasGeneratedMethods(descriptor_->file(), options_)) {
|
||||
// std::atomic has no copy constructor.
|
||||
format("\n, /*decltype($cached_byte_size_field$)*/{0}");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
123
libs/protobuf/src/google/protobuf/compiler/cpp/enum_field.h
Normal file
123
libs/protobuf/src/google/protobuf/compiler/cpp/enum_field.h
Normal file
@@ -0,0 +1,123 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "google/protobuf/compiler/cpp/field.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
class EnumFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
EnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options);
|
||||
EnumFieldGenerator(const EnumFieldGenerator&) = delete;
|
||||
EnumFieldGenerator& operator=(const EnumFieldGenerator&) = delete;
|
||||
~EnumFieldGenerator() override;
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const override;
|
||||
void GenerateAccessorDeclarations(io::Printer* printer) const override;
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
|
||||
void GenerateClearingCode(io::Printer* printer) const override;
|
||||
void GenerateMergingCode(io::Printer* printer) const override;
|
||||
void GenerateSwappingCode(io::Printer* printer) const override;
|
||||
void GenerateConstructorCode(io::Printer* printer) const override {}
|
||||
void GenerateCopyConstructorCode(io::Printer* printer) const override;
|
||||
void GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateByteSize(io::Printer* printer) const override;
|
||||
void GenerateConstexprAggregateInitializer(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateAggregateInitializer(io::Printer* printer) const override;
|
||||
void GenerateCopyAggregateInitializer(io::Printer* printer) const override;
|
||||
};
|
||||
|
||||
class EnumOneofFieldGenerator : public EnumFieldGenerator {
|
||||
public:
|
||||
EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options);
|
||||
EnumOneofFieldGenerator(const EnumOneofFieldGenerator&) = delete;
|
||||
EnumOneofFieldGenerator& operator=(const EnumOneofFieldGenerator&) = delete;
|
||||
~EnumOneofFieldGenerator() override;
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
|
||||
void GenerateClearingCode(io::Printer* printer) const override;
|
||||
void GenerateSwappingCode(io::Printer* printer) const override;
|
||||
void GenerateConstructorCode(io::Printer* printer) const override;
|
||||
};
|
||||
|
||||
class RepeatedEnumFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options);
|
||||
~RepeatedEnumFieldGenerator() override;
|
||||
RepeatedEnumFieldGenerator(const RepeatedEnumFieldGenerator&) = delete;
|
||||
RepeatedEnumFieldGenerator& operator=(const RepeatedEnumFieldGenerator&) =
|
||||
delete;
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const override;
|
||||
void GenerateAccessorDeclarations(io::Printer* printer) const override;
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
|
||||
void GenerateClearingCode(io::Printer* printer) const override;
|
||||
void GenerateMergingCode(io::Printer* printer) const override;
|
||||
void GenerateSwappingCode(io::Printer* printer) const override;
|
||||
void GenerateConstructorCode(io::Printer* printer) const override;
|
||||
void GenerateCopyConstructorCode(io::Printer* /*printer*/) const override {
|
||||
GOOGLE_CHECK(!ShouldSplit(descriptor_, options_));
|
||||
}
|
||||
void GenerateDestructorCode(io::Printer* printer) const override;
|
||||
void GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateByteSize(io::Printer* printer) const override;
|
||||
void GenerateConstexprAggregateInitializer(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateAggregateInitializer(io::Printer* printer) const override;
|
||||
void GenerateCopyAggregateInitializer(io::Printer* printer) const override;
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__
|
||||
194
libs/protobuf/src/google/protobuf/compiler/cpp/extension.cc
Normal file
194
libs/protobuf/src/google/protobuf/compiler/cpp/extension.cc
Normal file
@@ -0,0 +1,194 @@
|
||||
// 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/compiler/cpp/extension.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_replace.h"
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer)
|
||||
: descriptor_(descriptor), options_(options), scc_analyzer_(scc_analyzer) {
|
||||
// Construct type_traits_.
|
||||
if (descriptor_->is_repeated()) {
|
||||
type_traits_ = "Repeated";
|
||||
}
|
||||
|
||||
switch (descriptor_->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
type_traits_.append("EnumTypeTraits< ");
|
||||
type_traits_.append(ClassName(descriptor_->enum_type(), true));
|
||||
type_traits_.append(", ");
|
||||
type_traits_.append(ClassName(descriptor_->enum_type(), true));
|
||||
type_traits_.append("_IsValid>");
|
||||
break;
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
type_traits_.append("StringTypeTraits");
|
||||
break;
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
type_traits_.append("MessageTypeTraits< ");
|
||||
type_traits_.append(ClassName(descriptor_->message_type(), true));
|
||||
type_traits_.append(" >");
|
||||
break;
|
||||
default:
|
||||
type_traits_.append("PrimitiveTypeTraits< ");
|
||||
type_traits_.append(PrimitiveTypeName(options_, descriptor_->cpp_type()));
|
||||
type_traits_.append(" >");
|
||||
break;
|
||||
}
|
||||
SetCommonMessageDataVariables(descriptor_->containing_type(), &variables_);
|
||||
variables_["extendee"] =
|
||||
QualifiedClassName(descriptor_->containing_type(), options_);
|
||||
variables_["type_traits"] = type_traits_;
|
||||
std::string name = descriptor_->name();
|
||||
variables_["name"] = ResolveKeyword(name);
|
||||
variables_["constant_name"] = FieldConstantName(descriptor_);
|
||||
variables_["field_type"] =
|
||||
absl::StrCat(static_cast<int>(descriptor_->type()));
|
||||
variables_["packed"] = descriptor_->is_packed() ? "true" : "false";
|
||||
|
||||
std::string scope =
|
||||
IsScoped() ? ClassName(descriptor_->extension_scope(), false) + "::" : "";
|
||||
variables_["scope"] = scope;
|
||||
variables_["scoped_name"] = ExtensionName(descriptor_);
|
||||
variables_["number"] = absl::StrCat(descriptor_->number());
|
||||
|
||||
bool add_verify_fn =
|
||||
// Only verify msgs.
|
||||
descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
|
||||
// Options say to verify.
|
||||
ShouldVerify(descriptor_->message_type(), options_, scc_analyzer_) &&
|
||||
ShouldVerify(descriptor_->containing_type(), options_, scc_analyzer_);
|
||||
|
||||
variables_["verify_fn"] =
|
||||
add_verify_fn
|
||||
? absl::StrCat("&", FieldMessageTypeName(descriptor_, options_),
|
||||
"::InternalVerify")
|
||||
: "nullptr";
|
||||
}
|
||||
|
||||
ExtensionGenerator::~ExtensionGenerator() {}
|
||||
|
||||
bool ExtensionGenerator::IsScoped() const {
|
||||
return descriptor_->extension_scope() != nullptr;
|
||||
}
|
||||
|
||||
void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
|
||||
// If this is a class member, it needs to be declared "static". Otherwise,
|
||||
// it needs to be "extern". In the latter case, it also needs the DLL
|
||||
// export/import specifier.
|
||||
std::string qualifier;
|
||||
if (!IsScoped()) {
|
||||
qualifier = "extern";
|
||||
if (!options_.dllexport_decl.empty()) {
|
||||
qualifier = options_.dllexport_decl + " " + qualifier;
|
||||
}
|
||||
} else {
|
||||
qualifier = "static";
|
||||
}
|
||||
|
||||
format(
|
||||
"static const int $constant_name$ = $number$;\n"
|
||||
"$1$ ::$proto_ns$::internal::ExtensionIdentifier< $extendee$,\n"
|
||||
" ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$ >\n"
|
||||
" ${2$$name$$}$;\n",
|
||||
qualifier, descriptor_);
|
||||
}
|
||||
|
||||
void ExtensionGenerator::GenerateDefinition(io::Printer* printer) {
|
||||
// If we are building for lite with implicit weak fields, we want to skip over
|
||||
// any custom options (i.e. extensions of messages from descriptor.proto).
|
||||
// This prevents the creation of any unnecessary linker references to the
|
||||
// descriptor messages.
|
||||
if (options_.lite_implicit_weak_fields &&
|
||||
descriptor_->containing_type()->file()->name() ==
|
||||
"net/proto2/proto/descriptor.proto") {
|
||||
return;
|
||||
}
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
std::string default_str;
|
||||
// If this is a class member, it needs to be declared in its class scope.
|
||||
if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
|
||||
// We need to declare a global string which will contain the default value.
|
||||
// We cannot declare it at class scope because that would require exposing
|
||||
// it in the header which would be annoying for other reasons. So we
|
||||
// replace :: with _ in the name and declare it as a global.
|
||||
default_str =
|
||||
absl::StrReplaceAll(variables_["scoped_name"], {{"::", "_"}}) +
|
||||
"_default";
|
||||
format("const std::string $1$($2$);\n", default_str,
|
||||
DefaultValue(options_, descriptor_));
|
||||
} else if (descriptor_->message_type()) {
|
||||
// We have to initialize the default instance for extensions at registration
|
||||
// time.
|
||||
default_str =
|
||||
FieldMessageTypeName(descriptor_, options_) + "::default_instance()";
|
||||
} else {
|
||||
default_str = DefaultValue(options_, descriptor_);
|
||||
}
|
||||
|
||||
// Likewise, class members need to declare the field constant variable.
|
||||
if (IsScoped()) {
|
||||
format(
|
||||
"#if !defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)\n"
|
||||
"const int $scope$$constant_name$;\n"
|
||||
"#endif\n");
|
||||
}
|
||||
|
||||
format(
|
||||
"PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 "
|
||||
"::$proto_ns$::internal::ExtensionIdentifier< $extendee$,\n"
|
||||
" ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$>\n"
|
||||
" $scoped_name$($constant_name$, $1$, $verify_fn$);\n",
|
||||
default_str);
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
95
libs/protobuf/src/google/protobuf/compiler/cpp/extension.h
Normal file
95
libs/protobuf/src/google/protobuf/compiler/cpp/extension.h
Normal 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "google/protobuf/compiler/cpp/options.h"
|
||||
#include "google/protobuf/port.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
class FieldDescriptor; // descriptor.h
|
||||
namespace io {
|
||||
class Printer; // printer.h
|
||||
}
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
class MessageSCCAnalyzer;
|
||||
|
||||
// Generates code for an extension, which may be within the scope of some
|
||||
// message or may be at file scope. This is much simpler than FieldGenerator
|
||||
// since extensions are just simple identifiers with interesting types.
|
||||
class ExtensionGenerator {
|
||||
public:
|
||||
// See generator.cc for the meaning of dllexport_decl.
|
||||
explicit ExtensionGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer);
|
||||
ExtensionGenerator(const ExtensionGenerator&) = delete;
|
||||
ExtensionGenerator& operator=(const ExtensionGenerator&) = delete;
|
||||
~ExtensionGenerator();
|
||||
|
||||
// Header stuff.
|
||||
void GenerateDeclaration(io::Printer* printer) const;
|
||||
|
||||
// Source file stuff.
|
||||
void GenerateDefinition(io::Printer* printer);
|
||||
|
||||
bool IsScoped() const;
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
std::string type_traits_;
|
||||
Options options_;
|
||||
MessageSCCAnalyzer* scc_analyzer_;
|
||||
|
||||
std::map<std::string, std::string> variables_;
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
|
||||
448
libs/protobuf/src/google/protobuf/compiler/cpp/field.cc
Normal file
448
libs/protobuf/src/google/protobuf/compiler/cpp/field.cc
Normal file
@@ -0,0 +1,448 @@
|
||||
// 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/compiler/cpp/field.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/strings/substitute.h"
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
#include "google/protobuf/compiler/cpp/primitive_field.h"
|
||||
#include "google/protobuf/compiler/cpp/string_field.h"
|
||||
#include "google/protobuf/stubs/logging.h"
|
||||
#include "google/protobuf/stubs/common.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "google/protobuf/wire_format.h"
|
||||
#include "google/protobuf/compiler/cpp/enum_field.h"
|
||||
#include "google/protobuf/compiler/cpp/map_field.h"
|
||||
#include "google/protobuf/compiler/cpp/message_field.h"
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
using internal::WireFormat;
|
||||
|
||||
namespace {
|
||||
|
||||
void MaySetAnnotationVariable(const Options& options,
|
||||
absl::string_view annotation_name,
|
||||
absl::string_view substitute_template_prefix,
|
||||
absl::string_view prepared_template,
|
||||
int field_index, absl::string_view access_type,
|
||||
std::map<std::string, std::string>* variables) {
|
||||
if (options.field_listener_options.forbidden_field_listener_events.count(
|
||||
std::string(annotation_name)))
|
||||
return;
|
||||
(*variables)[absl::StrCat("annotate_", annotation_name)] = absl::Substitute(
|
||||
absl::StrCat(substitute_template_prefix, prepared_template, ");\n"),
|
||||
field_index, access_type);
|
||||
}
|
||||
|
||||
std::string GenerateTemplateForOneofString(const FieldDescriptor* descriptor,
|
||||
absl::string_view proto_ns,
|
||||
absl::string_view field_member) {
|
||||
std::string field_name = google::protobuf::compiler::cpp::FieldName(descriptor);
|
||||
std::string field_pointer =
|
||||
descriptor->options().ctype() == google::protobuf::FieldOptions::STRING
|
||||
? "$0.UnsafeGetPointer()"
|
||||
: "$0";
|
||||
|
||||
if (descriptor->default_value_string().empty()) {
|
||||
return absl::Substitute(absl::StrCat("_internal_has_", field_name, "() ? ",
|
||||
field_pointer, ": nullptr"),
|
||||
field_member);
|
||||
}
|
||||
|
||||
if (descriptor->options().ctype() == google::protobuf::FieldOptions::STRING_PIECE) {
|
||||
return absl::Substitute(absl::StrCat("_internal_has_", field_name, "() ? ",
|
||||
field_pointer, ": nullptr"),
|
||||
field_member);
|
||||
}
|
||||
|
||||
std::string default_value_pointer =
|
||||
descriptor->options().ctype() == google::protobuf::FieldOptions::STRING
|
||||
? "&$1.get()"
|
||||
: "&$1";
|
||||
return absl::Substitute(
|
||||
absl::StrCat("_internal_has_", field_name, "() ? ", field_pointer, " : ",
|
||||
default_value_pointer),
|
||||
field_member, MakeDefaultFieldName(descriptor));
|
||||
}
|
||||
|
||||
std::string GenerateTemplateForSingleString(const FieldDescriptor* descriptor,
|
||||
absl::string_view field_member) {
|
||||
if (descriptor->default_value_string().empty()) {
|
||||
return absl::StrCat("&", field_member);
|
||||
}
|
||||
|
||||
if (descriptor->options().ctype() == google::protobuf::FieldOptions::STRING) {
|
||||
return absl::Substitute(
|
||||
"$0.IsDefault() ? &$1.get() : $0.UnsafeGetPointer()", field_member,
|
||||
MakeDefaultFieldName(descriptor));
|
||||
}
|
||||
|
||||
return absl::StrCat("&", field_member);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void AddAccessorAnnotations(const FieldDescriptor* descriptor,
|
||||
const Options& options,
|
||||
std::map<std::string, std::string>* variables) {
|
||||
// Can be expanded to include more specific calls, for example, for arena or
|
||||
// clear calls.
|
||||
static constexpr const char* kAccessorsAnnotations[] = {
|
||||
"annotate_add", "annotate_get", "annotate_has",
|
||||
"annotate_list", "annotate_mutable", "annotate_mutable_list",
|
||||
"annotate_release", "annotate_set", "annotate_size",
|
||||
"annotate_clear", "annotate_add_mutable",
|
||||
};
|
||||
for (size_t i = 0; i < ABSL_ARRAYSIZE(kAccessorsAnnotations); ++i) {
|
||||
(*variables)[kAccessorsAnnotations[i]] = "";
|
||||
}
|
||||
if (options.annotate_accessor) {
|
||||
for (size_t i = 0; i < ABSL_ARRAYSIZE(kAccessorsAnnotations); ++i) {
|
||||
(*variables)[kAccessorsAnnotations[i]] = absl::StrCat(
|
||||
" ", FieldName(descriptor), "_AccessedNoStrip = true;\n");
|
||||
}
|
||||
}
|
||||
if (!options.field_listener_options.inject_field_listener_events) {
|
||||
return;
|
||||
}
|
||||
if (descriptor->file()->options().optimize_for() ==
|
||||
google::protobuf::FileOptions::LITE_RUNTIME) {
|
||||
return;
|
||||
}
|
||||
std::string field_member = (*variables)["field"];
|
||||
const google::protobuf::OneofDescriptor* oneof_member =
|
||||
descriptor->real_containing_oneof();
|
||||
const std::string substitute_template_prefix =
|
||||
absl::StrCat(" ", (*variables)["tracker"], ".$1<$0>(this, ");
|
||||
std::string prepared_template;
|
||||
|
||||
// Flat template is needed if the prepared one is introspecting the values
|
||||
// inside the returned values, for example, for repeated fields and maps.
|
||||
std::string prepared_flat_template;
|
||||
std::string prepared_add_template;
|
||||
// TODO(b/190614678): Support fields with type Message or Map.
|
||||
if (descriptor->is_repeated() && !descriptor->is_map()) {
|
||||
if (descriptor->type() != FieldDescriptor::TYPE_MESSAGE &&
|
||||
descriptor->type() != FieldDescriptor::TYPE_GROUP) {
|
||||
prepared_template = absl::Substitute("&$0.Get(index)", field_member);
|
||||
prepared_add_template =
|
||||
absl::Substitute("&$0.Get($0.size() - 1)", field_member);
|
||||
} else {
|
||||
prepared_template = "nullptr";
|
||||
prepared_add_template = "nullptr";
|
||||
}
|
||||
} else if (descriptor->is_map()) {
|
||||
prepared_template = "nullptr";
|
||||
} else if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE &&
|
||||
!IsExplicitLazy(descriptor)) {
|
||||
prepared_template = "nullptr";
|
||||
} else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
|
||||
if (oneof_member) {
|
||||
prepared_template = GenerateTemplateForOneofString(
|
||||
descriptor, ProtobufNamespace(options), field_member);
|
||||
} else {
|
||||
prepared_template =
|
||||
GenerateTemplateForSingleString(descriptor, field_member);
|
||||
}
|
||||
} else {
|
||||
prepared_template = absl::StrCat("&", field_member);
|
||||
}
|
||||
if (descriptor->is_repeated() && !descriptor->is_map() &&
|
||||
descriptor->type() != FieldDescriptor::TYPE_MESSAGE &&
|
||||
descriptor->type() != FieldDescriptor::TYPE_GROUP) {
|
||||
prepared_flat_template = absl::StrCat("&", field_member);
|
||||
} else {
|
||||
prepared_flat_template = prepared_template;
|
||||
}
|
||||
|
||||
MaySetAnnotationVariable(options, "get", substitute_template_prefix,
|
||||
prepared_template, descriptor->index(), "OnGet",
|
||||
variables);
|
||||
MaySetAnnotationVariable(options, "set", substitute_template_prefix,
|
||||
prepared_template, descriptor->index(), "OnSet",
|
||||
variables);
|
||||
MaySetAnnotationVariable(options, "has", substitute_template_prefix,
|
||||
prepared_template, descriptor->index(), "OnHas",
|
||||
variables);
|
||||
MaySetAnnotationVariable(options, "mutable", substitute_template_prefix,
|
||||
prepared_template, descriptor->index(), "OnMutable",
|
||||
variables);
|
||||
MaySetAnnotationVariable(options, "release", substitute_template_prefix,
|
||||
prepared_template, descriptor->index(), "OnRelease",
|
||||
variables);
|
||||
MaySetAnnotationVariable(options, "clear", substitute_template_prefix,
|
||||
prepared_flat_template, descriptor->index(),
|
||||
"OnClear", variables);
|
||||
MaySetAnnotationVariable(options, "size", substitute_template_prefix,
|
||||
prepared_flat_template, descriptor->index(),
|
||||
"OnSize", variables);
|
||||
MaySetAnnotationVariable(options, "list", substitute_template_prefix,
|
||||
prepared_flat_template, descriptor->index(),
|
||||
"OnList", variables);
|
||||
MaySetAnnotationVariable(options, "mutable_list", substitute_template_prefix,
|
||||
prepared_flat_template, descriptor->index(),
|
||||
"OnMutableList", variables);
|
||||
MaySetAnnotationVariable(options, "add", substitute_template_prefix,
|
||||
prepared_add_template, descriptor->index(), "OnAdd",
|
||||
variables);
|
||||
MaySetAnnotationVariable(options, "add_mutable", substitute_template_prefix,
|
||||
prepared_add_template, descriptor->index(),
|
||||
"OnAddMutable", variables);
|
||||
}
|
||||
|
||||
absl::flat_hash_map<std::string, std::string> FieldVars(
|
||||
const FieldDescriptor* desc, const Options& opts) {
|
||||
bool split = ShouldSplit(desc, opts);
|
||||
absl::flat_hash_map<std::string, std::string> vars = {
|
||||
{"ns", Namespace(desc, opts)},
|
||||
{"name", FieldName(desc)},
|
||||
{"index", absl::StrCat(desc->index())},
|
||||
{"number", absl::StrCat(desc->number())},
|
||||
{"classname", ClassName(FieldScope(desc), false)},
|
||||
{"declared_type", DeclaredTypeMethodName(desc->type())},
|
||||
{"field", FieldMemberName(desc, split)},
|
||||
{"tag_size",
|
||||
absl::StrCat(WireFormat::TagSize(desc->number(), desc->type()))},
|
||||
{"deprecated_attr", DeprecatedAttribute(opts, desc)},
|
||||
{"set_hasbit", ""},
|
||||
{"clear_hasbit", ""},
|
||||
{"maybe_prepare_split_message",
|
||||
split ? "PrepareSplitMessageForWrite();" : ""},
|
||||
|
||||
// These variables are placeholders to pick out the beginning and ends of
|
||||
// identifiers for annotations (when doing so with existing variables
|
||||
// would be ambiguous or impossible). They should never be set to anything
|
||||
// but the empty string.
|
||||
{"{", ""},
|
||||
{"}", ""},
|
||||
};
|
||||
|
||||
// TODO(b/245791219): Refactor AddAccessorAnnotations to avoid this
|
||||
// workaround.
|
||||
std::map<std::string, std::string> workaround = {
|
||||
{"field", vars["field"]},
|
||||
{"tracker", "Impl_::_tracker_"},
|
||||
};
|
||||
AddAccessorAnnotations(desc, opts, &workaround);
|
||||
for (auto& pair : workaround) {
|
||||
vars.emplace(pair);
|
||||
}
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
|
||||
std::map<std::string, std::string>* variables,
|
||||
const Options& options) {
|
||||
SetCommonMessageDataVariables(descriptor->containing_type(), variables);
|
||||
|
||||
for (auto& pair : FieldVars(descriptor, options)) {
|
||||
variables->emplace(pair);
|
||||
}
|
||||
}
|
||||
|
||||
absl::flat_hash_map<std::string, std::string> OneofFieldVars(
|
||||
const FieldDescriptor* descriptor) {
|
||||
if (descriptor->containing_oneof() == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {{"oneof_name", descriptor->containing_oneof()->name()}};
|
||||
}
|
||||
|
||||
void SetCommonOneofFieldVariables(
|
||||
const FieldDescriptor* descriptor,
|
||||
std::map<std::string, std::string>* variables) {
|
||||
for (auto& pair : OneofFieldVars(descriptor)) {
|
||||
variables->emplace(pair);
|
||||
}
|
||||
}
|
||||
|
||||
void FieldGenerator::SetHasBitIndex(int32_t has_bit_index) {
|
||||
if (!internal::cpp::HasHasbit(descriptor_)) {
|
||||
GOOGLE_CHECK_EQ(has_bit_index, -1);
|
||||
return;
|
||||
}
|
||||
variables_["set_hasbit"] = absl::StrCat(
|
||||
variables_["has_bits"], "[", has_bit_index / 32, "] |= 0x",
|
||||
absl::Hex(1u << (has_bit_index % 32), absl::kZeroPad8), "u;");
|
||||
variables_["clear_hasbit"] = absl::StrCat(
|
||||
variables_["has_bits"], "[", has_bit_index / 32, "] &= ~0x",
|
||||
absl::Hex(1u << (has_bit_index % 32), absl::kZeroPad8), "u;");
|
||||
}
|
||||
|
||||
void FieldGenerator::SetInlinedStringIndex(int32_t inlined_string_index) {
|
||||
if (!IsStringInlined(descriptor_, options_)) {
|
||||
GOOGLE_CHECK_EQ(inlined_string_index, -1);
|
||||
return;
|
||||
}
|
||||
// The first bit is the tracking bit for on demand registering ArenaDtor.
|
||||
GOOGLE_CHECK_GT(inlined_string_index, 0)
|
||||
<< "_inlined_string_donated_'s bit 0 is reserved for arena dtor tracking";
|
||||
variables_["inlined_string_donated"] = absl::StrCat(
|
||||
"(", variables_["inlined_string_donated_array"], "[",
|
||||
inlined_string_index / 32, "] & 0x",
|
||||
absl::Hex(1u << (inlined_string_index % 32), absl::kZeroPad8),
|
||||
"u) != 0;");
|
||||
variables_["donating_states_word"] =
|
||||
absl::StrCat(variables_["inlined_string_donated_array"], "[",
|
||||
inlined_string_index / 32, "]");
|
||||
variables_["mask_for_undonate"] = absl::StrCat(
|
||||
"~0x", absl::Hex(1u << (inlined_string_index % 32), absl::kZeroPad8),
|
||||
"u");
|
||||
}
|
||||
|
||||
void FieldGenerator::GenerateAggregateInitializer(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("decltype(Impl_::Split::$name$_){arena}");
|
||||
return;
|
||||
}
|
||||
format("decltype($field$){arena}");
|
||||
}
|
||||
|
||||
void FieldGenerator::GenerateConstexprAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("/*decltype($field$)*/{}");
|
||||
}
|
||||
|
||||
void FieldGenerator::GenerateCopyAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("decltype($field$){from.$field$}");
|
||||
}
|
||||
|
||||
void FieldGenerator::GenerateCopyConstructorCode(io::Printer* printer) const {
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
// There is no copy constructor for the `Split` struct, so we need to copy
|
||||
// the value here.
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$ = from.$field$;\n");
|
||||
}
|
||||
}
|
||||
|
||||
FieldGenerator::~FieldGenerator() {}
|
||||
|
||||
FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor,
|
||||
const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer)
|
||||
: descriptor_(descriptor), field_generators_(descriptor->field_count()) {
|
||||
// Construct all the FieldGenerators.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
field_generators_[i].reset(
|
||||
MakeGenerator(descriptor->field(i), options, scc_analyzer));
|
||||
}
|
||||
}
|
||||
|
||||
FieldGenerator* FieldGeneratorMap::MakeGoogleInternalGenerator(
|
||||
const FieldDescriptor* field, const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer) {
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FieldGenerator* FieldGeneratorMap::MakeGenerator(
|
||||
const FieldDescriptor* field, const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer) {
|
||||
FieldGenerator* generator =
|
||||
MakeGoogleInternalGenerator(field, options, scc_analyzer);
|
||||
if (generator) {
|
||||
return generator;
|
||||
}
|
||||
|
||||
if (field->is_repeated()) {
|
||||
switch (field->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
if (field->is_map()) {
|
||||
return new MapFieldGenerator(field, options, scc_analyzer);
|
||||
} else {
|
||||
return new RepeatedMessageFieldGenerator(field, options,
|
||||
scc_analyzer);
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
return new RepeatedStringFieldGenerator(field, options);
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
return new RepeatedEnumFieldGenerator(field, options);
|
||||
default:
|
||||
return new RepeatedPrimitiveFieldGenerator(field, options);
|
||||
}
|
||||
} else if (field->real_containing_oneof()) {
|
||||
switch (field->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
return new MessageOneofFieldGenerator(field, options, scc_analyzer);
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
return new StringOneofFieldGenerator(field, options);
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
return new EnumOneofFieldGenerator(field, options);
|
||||
default:
|
||||
return new PrimitiveOneofFieldGenerator(field, options);
|
||||
}
|
||||
} else {
|
||||
switch (field->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
return new MessageFieldGenerator(field, options, scc_analyzer);
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
return new StringFieldGenerator(field, options);
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
return new EnumFieldGenerator(field, options);
|
||||
default:
|
||||
return new PrimitiveFieldGenerator(field, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FieldGeneratorMap::~FieldGeneratorMap() {}
|
||||
|
||||
const FieldGenerator& FieldGeneratorMap::get(
|
||||
const FieldDescriptor* field) const {
|
||||
GOOGLE_CHECK_EQ(field->containing_type(), descriptor_);
|
||||
return *field_generators_[field->index()];
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
272
libs/protobuf/src/google/protobuf/compiler/cpp/field.h
Normal file
272
libs/protobuf/src/google/protobuf/compiler/cpp/field.h
Normal file
@@ -0,0 +1,272 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
#include "google/protobuf/compiler/cpp/options.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
class Printer; // printer.h
|
||||
}
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
absl::flat_hash_map<std::string, std::string> FieldVars(
|
||||
const FieldDescriptor* desc, const Options& opts);
|
||||
|
||||
absl::flat_hash_map<std::string, std::string> OneofFieldVars(
|
||||
const FieldDescriptor* descriptor);
|
||||
|
||||
// Helper function: set variables in the map that are the same for all
|
||||
// field code generators.
|
||||
// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size',
|
||||
// 'deprecation'].
|
||||
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
|
||||
std::map<std::string, std::string>* variables,
|
||||
const Options& options);
|
||||
|
||||
void SetCommonOneofFieldVariables(
|
||||
const FieldDescriptor* descriptor,
|
||||
std::map<std::string, std::string>* variables);
|
||||
|
||||
class FieldGenerator {
|
||||
public:
|
||||
explicit FieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options)
|
||||
: descriptor_(descriptor), options_(options) {}
|
||||
FieldGenerator(const FieldGenerator&) = delete;
|
||||
FieldGenerator& operator=(const FieldGenerator&) = delete;
|
||||
virtual ~FieldGenerator();
|
||||
virtual void GenerateSerializeWithCachedSizes(
|
||||
io::Printer* printer) const final{};
|
||||
// Generate lines of code declaring members fields of the message class
|
||||
// needed to represent this field. These are placed inside the message
|
||||
// class.
|
||||
virtual void GeneratePrivateMembers(io::Printer* printer) const = 0;
|
||||
|
||||
// Generate static default variable for this field. These are placed inside
|
||||
// the message class. Most field types don't need this, so the default
|
||||
// implementation is empty.
|
||||
virtual void GenerateStaticMembers(io::Printer* /*printer*/) const {}
|
||||
|
||||
// Generate prototypes for all of the accessor functions related to this
|
||||
// field. These are placed inside the class definition.
|
||||
virtual void GenerateAccessorDeclarations(io::Printer* printer) const = 0;
|
||||
|
||||
// Generate inline definitions of accessor functions for this field.
|
||||
// These are placed inside the header after all class definitions.
|
||||
virtual void GenerateInlineAccessorDefinitions(
|
||||
io::Printer* printer) const = 0;
|
||||
|
||||
// Generate definitions of accessors that aren't inlined. These are
|
||||
// placed somewhere in the .cc file.
|
||||
// Most field types don't need this, so the default implementation is empty.
|
||||
virtual void GenerateNonInlineAccessorDefinitions(
|
||||
io::Printer* /*printer*/) const {}
|
||||
|
||||
// Generate declarations of accessors that are for internal purposes only.
|
||||
// Most field types don't need this, so the default implementation is empty.
|
||||
virtual void GenerateInternalAccessorDefinitions(
|
||||
io::Printer* /*printer*/) const {}
|
||||
|
||||
// Generate definitions of accessors that are for internal purposes only.
|
||||
// Most field types don't need this, so the default implementation is empty.
|
||||
virtual void GenerateInternalAccessorDeclarations(
|
||||
io::Printer* /*printer*/) const {}
|
||||
|
||||
// Generate lines of code (statements, not declarations) which clear the
|
||||
// field. This is used to define the clear_$name$() method
|
||||
virtual void GenerateClearingCode(io::Printer* printer) const = 0;
|
||||
|
||||
// Generate lines of code (statements, not declarations) which clear the
|
||||
// field as part of the Clear() method for the whole message. For message
|
||||
// types which have field presence bits, MessageGenerator::GenerateClear
|
||||
// will have already checked the presence bits.
|
||||
//
|
||||
// Since most field types can re-use GenerateClearingCode, this method is
|
||||
// not pure virtual.
|
||||
virtual void GenerateMessageClearingCode(io::Printer* printer) const {
|
||||
GenerateClearingCode(printer);
|
||||
}
|
||||
|
||||
// Generate lines of code (statements, not declarations) which merges the
|
||||
// contents of the field from the current message to the target message,
|
||||
// which is stored in the generated code variable "from".
|
||||
// This is used to fill in the MergeFrom method for the whole message.
|
||||
// Details of this usage can be found in message.cc under the
|
||||
// GenerateMergeFrom method.
|
||||
virtual void GenerateMergingCode(io::Printer* printer) const = 0;
|
||||
|
||||
// Generates a copy constructor
|
||||
virtual void GenerateCopyConstructorCode(io::Printer* printer) const;
|
||||
|
||||
// Generate lines of code (statements, not declarations) which swaps
|
||||
// this field and the corresponding field of another message, which
|
||||
// is stored in the generated code variable "other". This is used to
|
||||
// define the Swap method. Details of usage can be found in
|
||||
// message.cc under the GenerateSwap method.
|
||||
virtual void GenerateSwappingCode(io::Printer* printer) const = 0;
|
||||
|
||||
// Generate initialization code for private members declared by
|
||||
// GeneratePrivateMembers(). These go into the message class's SharedCtor()
|
||||
// method, invoked by each of the generated constructors.
|
||||
virtual void GenerateConstructorCode(io::Printer* printer) const = 0;
|
||||
|
||||
// Generate any code that needs to go in the class's SharedDtor() method,
|
||||
// invoked by the destructor.
|
||||
// Most field types don't need this, so the default implementation is empty.
|
||||
virtual void GenerateDestructorCode(io::Printer* /*printer*/) const {}
|
||||
|
||||
// Generate a manual destructor invocation for use when the message is on an
|
||||
// arena. The code that this method generates will be executed inside a
|
||||
// shared-for-the-whole-message-class method registered with
|
||||
// OwnDestructor().
|
||||
virtual void GenerateArenaDestructorCode(io::Printer* printer) const {
|
||||
GOOGLE_CHECK(NeedsArenaDestructor() == ArenaDtorNeeds::kNone)
|
||||
<< descriptor_->cpp_type_name();
|
||||
}
|
||||
|
||||
// Generate initialization code for private members declared by
|
||||
// GeneratePrivateMembers(). These go into the SharedCtor's
|
||||
// aggregate initialization of the _impl_ struct and must follow the syntax
|
||||
// (e.g. `decltype($field$){$default$}`). Does not include `:` or `,`
|
||||
// separators. Default values should be specified here when possible.
|
||||
//
|
||||
// Note: We use `decltype($field$)` for both explicit construction and the
|
||||
// fact that it's self-documenting. Pre-C++17, copy elision isn't guaranteed
|
||||
// in aggregate initialization so a valid copy/move constructor must exist
|
||||
// (even though it's not used). Because of this, we need to comment out the
|
||||
// decltype and fallback to implicit construction.
|
||||
virtual void GenerateAggregateInitializer(io::Printer* printer) const;
|
||||
|
||||
// Generate constinit initialization code for private members declared by
|
||||
// GeneratePrivateMembers(). These go into the constexpr constructor's
|
||||
// aggregate initialization of the _impl_ struct and must follow the syntax
|
||||
// (e.g. `/*decltype($field$)*/{}`, see above). Does not
|
||||
// include `:` or `,` separators.
|
||||
virtual void GenerateConstexprAggregateInitializer(
|
||||
io::Printer* printer) const;
|
||||
|
||||
// Generate copy initialization code for private members declared by
|
||||
// GeneratePrivateMembers(). These go into the copy constructor's
|
||||
// aggregate initialization of the _impl_ struct and must follow the syntax
|
||||
// (e.g. `decltype($field$){from.$field$}`, see above). Does not
|
||||
// include `:` or `,` separators.
|
||||
virtual void GenerateCopyAggregateInitializer(io::Printer* printer) const;
|
||||
|
||||
// Generate lines to serialize this field directly to the array "target",
|
||||
// which are placed within the message's SerializeWithCachedSizesToArray()
|
||||
// method. This must also advance "target" past the written bytes.
|
||||
virtual void GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const = 0;
|
||||
|
||||
// Generate lines to compute the serialized size of this field, which
|
||||
// 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; }
|
||||
|
||||
virtual ArenaDtorNeeds NeedsArenaDestructor() const {
|
||||
return ArenaDtorNeeds::kNone;
|
||||
}
|
||||
|
||||
void SetHasBitIndex(int32_t has_bit_index);
|
||||
void SetInlinedStringIndex(int32_t inlined_string_index);
|
||||
|
||||
protected:
|
||||
const FieldDescriptor* descriptor_;
|
||||
const Options& options_;
|
||||
std::map<std::string, std::string> variables_;
|
||||
};
|
||||
|
||||
// Convenience class which constructs FieldGenerators for a Descriptor.
|
||||
class FieldGeneratorMap {
|
||||
public:
|
||||
FieldGeneratorMap(const Descriptor* descriptor, const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer);
|
||||
FieldGeneratorMap(const FieldGeneratorMap&) = delete;
|
||||
FieldGeneratorMap& operator=(const FieldGeneratorMap&) = delete;
|
||||
~FieldGeneratorMap();
|
||||
|
||||
const FieldGenerator& get(const FieldDescriptor* field) const;
|
||||
|
||||
void SetHasBitIndices(const std::vector<int>& has_bit_indices_) {
|
||||
for (int i = 0; i < descriptor_->field_count(); ++i) {
|
||||
field_generators_[i]->SetHasBitIndex(has_bit_indices_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void SetInlinedStringIndices(const std::vector<int>& inlined_string_indices) {
|
||||
for (int i = 0; i < descriptor_->field_count(); ++i) {
|
||||
field_generators_[i]->SetInlinedStringIndex(inlined_string_indices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const Descriptor* descriptor_;
|
||||
std::vector<std::unique_ptr<FieldGenerator>> field_generators_;
|
||||
|
||||
static FieldGenerator* MakeGoogleInternalGenerator(
|
||||
const FieldDescriptor* field, const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer);
|
||||
static FieldGenerator* MakeGenerator(const FieldDescriptor* field,
|
||||
const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer);
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
|
||||
1505
libs/protobuf/src/google/protobuf/compiler/cpp/file.cc
Normal file
1505
libs/protobuf/src/google/protobuf/compiler/cpp/file.cc
Normal file
File diff suppressed because it is too large
Load Diff
213
libs/protobuf/src/google/protobuf/compiler/cpp/file.h
Normal file
213
libs/protobuf/src/google/protobuf/compiler/cpp/file.h
Normal file
@@ -0,0 +1,213 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "google/protobuf/stubs/common.h"
|
||||
#include "google/protobuf/compiler/scc.h"
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
#include "google/protobuf/compiler/cpp/enum.h"
|
||||
#include "google/protobuf/compiler/cpp/extension.h"
|
||||
#include "google/protobuf/compiler/cpp/field.h"
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
#include "google/protobuf/compiler/cpp/message.h"
|
||||
#include "google/protobuf/compiler/cpp/options.h"
|
||||
#include "google/protobuf/compiler/cpp/service.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "google/protobuf/port.h"
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
class FileGenerator {
|
||||
public:
|
||||
FileGenerator(const FileDescriptor* file, const Options& options);
|
||||
|
||||
FileGenerator(const FileGenerator&) = delete;
|
||||
FileGenerator& operator=(const FileGenerator&) = delete;
|
||||
|
||||
~FileGenerator() = default;
|
||||
|
||||
// info_path, if non-empty, should be the path (relative to printer's
|
||||
// output) to the metadata file describing this proto header.
|
||||
void GenerateProtoHeader(io::Printer* p, absl::string_view info_path);
|
||||
// info_path, if non-empty, should be the path (relative to printer's
|
||||
// output) to the metadata file describing this PB header.
|
||||
void GeneratePBHeader(io::Printer* p, absl::string_view info_path);
|
||||
void GenerateSource(io::Printer* p);
|
||||
|
||||
// The following member functions are used when the lite_implicit_weak_fields
|
||||
// option is set. In this mode the code is organized a bit differently to
|
||||
// promote better linker stripping of unused code. In particular, we generate
|
||||
// one .cc file per message, one .cc file per extension, and a main pb.cc file
|
||||
// containing everything else.
|
||||
|
||||
int NumMessages() const { return message_generators_.size(); }
|
||||
int NumExtensions() const { return extension_generators_.size(); }
|
||||
// Generates the source file for one message.
|
||||
void GenerateSourceForMessage(int idx, io::Printer* p);
|
||||
// Generates the source file for one extension.
|
||||
void GenerateSourceForExtension(int idx, io::Printer* p);
|
||||
// Generates a source file containing everything except messages and
|
||||
// extensions.
|
||||
void GenerateGlobalSource(io::Printer* p);
|
||||
|
||||
private:
|
||||
// Generates a file, setting up the necessary accoutrements that start and
|
||||
// end the file, calling `cb` in between.
|
||||
//
|
||||
// This includes header guards and file-global variables.
|
||||
void GenerateFile(io::Printer* p, GeneratedFileType file_type,
|
||||
std::function<void()> cb);
|
||||
|
||||
// Shared code between the two header generators.
|
||||
void GenerateSharedHeaderCode(io::Printer* p);
|
||||
|
||||
// Internal type used by GenerateForwardDeclarations (defined in file.cc).
|
||||
class ForwardDeclarations;
|
||||
struct CrossFileReferences;
|
||||
|
||||
void IncludeFile(absl::string_view google3_name, io::Printer* p) {
|
||||
DoIncludeFile(google3_name, false, p);
|
||||
}
|
||||
void IncludeFileAndExport(absl::string_view google3_name, io::Printer* p) {
|
||||
DoIncludeFile(google3_name, true, p);
|
||||
}
|
||||
void DoIncludeFile(absl::string_view google3_name, bool do_export,
|
||||
io::Printer* p);
|
||||
|
||||
std::string CreateHeaderInclude(absl::string_view basename,
|
||||
const FileDescriptor* file);
|
||||
void GetCrossFileReferencesForField(const FieldDescriptor* field,
|
||||
CrossFileReferences* refs);
|
||||
void GetCrossFileReferencesForFile(const FileDescriptor* file,
|
||||
CrossFileReferences* refs);
|
||||
void GenerateInternalForwardDeclarations(const CrossFileReferences& refs,
|
||||
io::Printer* p);
|
||||
void GenerateSourceIncludes(io::Printer* p);
|
||||
void GenerateSourcePrelude(io::Printer* p);
|
||||
void GenerateSourceDefaultInstance(int idx, io::Printer* p);
|
||||
|
||||
void GenerateInitForSCC(const SCC* scc, const CrossFileReferences& refs,
|
||||
io::Printer* p);
|
||||
void GenerateReflectionInitializationCode(io::Printer* p);
|
||||
|
||||
// For other imports, generates their forward-declarations.
|
||||
void GenerateForwardDeclarations(io::Printer* p);
|
||||
|
||||
// Generates top or bottom of a header file.
|
||||
void GenerateTopHeaderGuard(io::Printer* p, GeneratedFileType file_type);
|
||||
void GenerateBottomHeaderGuard(io::Printer* p, GeneratedFileType file_type);
|
||||
|
||||
// Generates #include directives.
|
||||
void GenerateLibraryIncludes(io::Printer* p);
|
||||
void GenerateDependencyIncludes(io::Printer* p);
|
||||
|
||||
// Generate a pragma to pull in metadata using the given info_path (if
|
||||
// non-empty). info_path should be relative to printer's output.
|
||||
void GenerateMetadataPragma(io::Printer* p, absl::string_view info_path);
|
||||
|
||||
// Generates a couple of different pieces before definitions:
|
||||
void GenerateGlobalStateFunctionDeclarations(io::Printer* p);
|
||||
|
||||
// Generates types for classes.
|
||||
void GenerateMessageDefinitions(io::Printer* p);
|
||||
|
||||
void GenerateEnumDefinitions(io::Printer* p);
|
||||
|
||||
// Generates generic service definitions.
|
||||
void GenerateServiceDefinitions(io::Printer* p);
|
||||
|
||||
// Generates extension identifiers.
|
||||
void GenerateExtensionIdentifiers(io::Printer* p);
|
||||
|
||||
// Generates inline function definitions.
|
||||
void GenerateInlineFunctionDefinitions(io::Printer* p);
|
||||
|
||||
void GenerateProto2NamespaceEnumSpecializations(io::Printer* p);
|
||||
|
||||
// Sometimes the names we use in a .proto file happen to be defined as
|
||||
// macros on some platforms (e.g., macro/minor used in plugin.proto are
|
||||
// defined as macros in sys/types.h on FreeBSD and a few other platforms).
|
||||
// To make the generated code compile on these platforms, we either have to
|
||||
// undef the macro for these few platforms, or rename the field name for all
|
||||
// platforms. Since these names are part of protobuf public API, renaming is
|
||||
// generally a breaking change so we prefer the #undef approach.
|
||||
void GenerateMacroUndefs(io::Printer* p);
|
||||
|
||||
bool IsDepWeak(const FileDescriptor* dep) const {
|
||||
if (weak_deps_.count(dep) != 0) {
|
||||
GOOGLE_CHECK(!options_.opensource_runtime);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
absl::flat_hash_set<const FileDescriptor*> weak_deps_;
|
||||
|
||||
const FileDescriptor* file_;
|
||||
Options options_;
|
||||
|
||||
MessageSCCAnalyzer scc_analyzer_;
|
||||
|
||||
// This member is unused and should be deleted once all old-style variable
|
||||
// maps are gone.
|
||||
// TODO(b/245791219)
|
||||
std::map<std::string, std::string> variables_;
|
||||
|
||||
// Contains the post-order walk of all the messages (and child messages) in
|
||||
// this file. If you need a pre-order walk just reverse iterate.
|
||||
std::vector<std::unique_ptr<MessageGenerator>> message_generators_;
|
||||
std::vector<std::unique_ptr<EnumGenerator>> enum_generators_;
|
||||
std::vector<std::unique_ptr<ServiceGenerator>> service_generators_;
|
||||
std::vector<std::unique_ptr<ExtensionGenerator>> extension_generators_;
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
|
||||
348
libs/protobuf/src/google/protobuf/compiler/cpp/generator.cc
Normal file
348
libs/protobuf/src/google/protobuf/compiler/cpp/generator.cc
Normal file
@@ -0,0 +1,348 @@
|
||||
// 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/compiler/cpp/generator.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "google/protobuf/stubs/strutil.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "google/protobuf/io/zero_copy_stream.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_replace.h"
|
||||
#include "google/protobuf/compiler/cpp/file.h"
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
namespace {
|
||||
std::string NumberedCcFileName(absl::string_view basename, int number) {
|
||||
return absl::StrCat(basename, ".out/", number, ".cc");
|
||||
}
|
||||
|
||||
absl::flat_hash_map<std::string, std::string> CommonVars(
|
||||
const Options& options) {
|
||||
bool is_oss = options.opensource_runtime;
|
||||
return {
|
||||
{"proto_ns", ProtobufNamespace(options)},
|
||||
{"string", "std::string"},
|
||||
{"int8", "int8_t"},
|
||||
{"int32", "int32_t"},
|
||||
{"int64", "int64_t"},
|
||||
{"uint8", "uint8_t"},
|
||||
{"uint32", "uint32_t"},
|
||||
{"uint64", "uint64_t"},
|
||||
|
||||
{"hrule_thick", kThickSeparator},
|
||||
{"hrule_thin", kThinSeparator},
|
||||
|
||||
// Warning: there is some clever naming/splitting here to avoid extract
|
||||
// script rewrites. The names of these variables must not be things that
|
||||
// the extract script will rewrite. That's why we use "CHK" (for example)
|
||||
// instead of "GOOGLE_CHECK".
|
||||
//
|
||||
// These values are things the extract script would rewrite if we did not
|
||||
// split them. It might not strictly matter since we don't generate
|
||||
// google3 code in open-source. But it's good to prevent surprising
|
||||
// things from happening.
|
||||
{"GOOGLE_PROTOBUF", is_oss ? "GOOGLE_PROTOBUF"
|
||||
: "GOOGLE3_PROTOBU"
|
||||
"F"},
|
||||
{"CHK", is_oss ? "GOOGLE_CHECK"
|
||||
: "CHEC"
|
||||
"K"},
|
||||
{"DCHK", is_oss ? "GOOGLE_DCHECK"
|
||||
: "DCHEC"
|
||||
"K"},
|
||||
};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool CppGenerator::Generate(const FileDescriptor* file,
|
||||
const std::string& parameter,
|
||||
GeneratorContext* generator_context,
|
||||
std::string* error) const {
|
||||
std::vector<std::pair<std::string, std::string>> options;
|
||||
ParseGeneratorParameter(parameter, &options);
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// parse generator options
|
||||
|
||||
// If the dllexport_decl option is passed to the compiler, we need to write
|
||||
// it in front of every symbol that should be exported if this .proto is
|
||||
// compiled into a Windows DLL. E.g., if the user invokes the protocol
|
||||
// compiler as:
|
||||
// protoc --cpp_out=dllexport_decl=FOO_EXPORT:outdir foo.proto
|
||||
// then we'll define classes like this:
|
||||
// class FOO_EXPORT Foo {
|
||||
// ...
|
||||
// }
|
||||
// FOO_EXPORT is a macro which should expand to __declspec(dllexport) or
|
||||
// __declspec(dllimport) depending on what is being compiled.
|
||||
//
|
||||
// If the proto_h option is passed to the compiler, we will generate all
|
||||
// classes and enums so that they can be forward-declared from files that
|
||||
// need them from imports.
|
||||
//
|
||||
// If the lite option is passed to the compiler, we will generate the
|
||||
// current files and all transitive dependencies using the LITE runtime.
|
||||
Options file_options;
|
||||
|
||||
file_options.opensource_runtime = opensource_runtime_;
|
||||
file_options.runtime_include_base = runtime_include_base_;
|
||||
|
||||
for (const auto& option : options) {
|
||||
const auto& key = option.first;
|
||||
const auto& value = option.second;
|
||||
|
||||
if (key == "dllexport_decl") {
|
||||
file_options.dllexport_decl = value;
|
||||
} else if (key == "safe_boundary_check") {
|
||||
file_options.safe_boundary_check = true;
|
||||
} else if (key == "annotate_headers") {
|
||||
file_options.annotate_headers = true;
|
||||
} else if (key == "annotation_pragma_name") {
|
||||
file_options.annotation_pragma_name = value;
|
||||
} else if (key == "annotation_guard_name") {
|
||||
file_options.annotation_guard_name = value;
|
||||
} else if (key == "speed") {
|
||||
file_options.enforce_mode = EnforceOptimizeMode::kSpeed;
|
||||
} else if (key == "code_size") {
|
||||
file_options.enforce_mode = EnforceOptimizeMode::kCodeSize;
|
||||
} else if (key == "lite") {
|
||||
file_options.enforce_mode = EnforceOptimizeMode::kLiteRuntime;
|
||||
} else if (key == "lite_implicit_weak_fields") {
|
||||
file_options.enforce_mode = EnforceOptimizeMode::kLiteRuntime;
|
||||
file_options.lite_implicit_weak_fields = true;
|
||||
if (!value.empty()) {
|
||||
file_options.num_cc_files = strto32(value.c_str(), nullptr, 10);
|
||||
}
|
||||
} else if (key == "proto_h") {
|
||||
file_options.proto_h = true;
|
||||
} else if (key == "proto_static_reflection_h") {
|
||||
} else if (key == "annotate_accessor") {
|
||||
file_options.annotate_accessor = true;
|
||||
} else if (key == "inject_field_listener_events") {
|
||||
file_options.field_listener_options.inject_field_listener_events = true;
|
||||
} else if (key == "forbidden_field_listener_events") {
|
||||
std::size_t pos = 0;
|
||||
do {
|
||||
std::size_t next_pos = value.find_first_of("+", pos);
|
||||
if (next_pos == std::string::npos) {
|
||||
next_pos = value.size();
|
||||
}
|
||||
if (next_pos > pos)
|
||||
file_options.field_listener_options.forbidden_field_listener_events
|
||||
.insert(value.substr(pos, next_pos - pos));
|
||||
pos = next_pos + 1;
|
||||
} while (pos < value.size());
|
||||
} else if (key == "unverified_lazy_message_sets") {
|
||||
file_options.unverified_lazy_message_sets = true;
|
||||
} else if (key == "message_owned_arena_trial") {
|
||||
file_options.message_owned_arena_trial = true;
|
||||
} else if (key == "force_eagerly_verified_lazy") {
|
||||
file_options.force_eagerly_verified_lazy = true;
|
||||
} else if (key == "experimental_tail_call_table_mode") {
|
||||
if (value == "never") {
|
||||
file_options.tctable_mode = Options::kTCTableNever;
|
||||
} else if (value == "guarded") {
|
||||
file_options.tctable_mode = Options::kTCTableGuarded;
|
||||
} else if (value == "always") {
|
||||
file_options.tctable_mode = Options::kTCTableAlways;
|
||||
} else {
|
||||
*error =
|
||||
"Unknown value for experimental_tail_call_table_mode: " + value;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
*error = "Unknown generator option: " + key;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The safe_boundary_check option controls behavior for Google-internal
|
||||
// protobuf APIs.
|
||||
if (file_options.safe_boundary_check && file_options.opensource_runtime) {
|
||||
*error =
|
||||
"The safe_boundary_check option is not supported outside of Google.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
|
||||
std::string basename = StripProto(file->name());
|
||||
|
||||
auto generate_reserved_static_reflection_header = [&basename,
|
||||
&generator_context]() {
|
||||
auto output = absl::WrapUnique(generator_context->Open(
|
||||
absl::StrCat(basename, ".proto.static_reflection.h")));
|
||||
io::Printer(output.get()).Emit(R"cc(
|
||||
// Reserved for future use.
|
||||
)cc");
|
||||
};
|
||||
// Suppress maybe unused warning.
|
||||
(void)generate_reserved_static_reflection_header;
|
||||
|
||||
if (MaybeBootstrap(file_options, generator_context, file_options.bootstrap,
|
||||
&basename)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
FileGenerator file_generator(file, file_options);
|
||||
|
||||
// Generate header(s).
|
||||
if (file_options.proto_h) {
|
||||
auto output = absl::WrapUnique(
|
||||
generator_context->Open(absl::StrCat(basename, ".proto.h")));
|
||||
|
||||
GeneratedCodeInfo annotations;
|
||||
io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
|
||||
&annotations);
|
||||
io::Printer::Options options;
|
||||
if (file_options.annotate_headers) {
|
||||
options.annotation_collector = &annotation_collector;
|
||||
}
|
||||
|
||||
io::Printer p(output.get(), options);
|
||||
auto v = p.WithVars(CommonVars(file_options));
|
||||
|
||||
std::string info_path = absl::StrCat(basename, ".proto.h.meta");
|
||||
file_generator.GenerateProtoHeader(
|
||||
&p, file_options.annotate_headers ? info_path : "");
|
||||
|
||||
if (file_options.annotate_headers) {
|
||||
auto info_output = absl::WrapUnique(generator_context->Open(info_path));
|
||||
annotations.SerializeToZeroCopyStream(info_output.get());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto output = absl::WrapUnique(
|
||||
generator_context->Open(absl::StrCat(basename, ".pb.h")));
|
||||
|
||||
GeneratedCodeInfo annotations;
|
||||
io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
|
||||
&annotations);
|
||||
io::Printer::Options options;
|
||||
if (file_options.annotate_headers) {
|
||||
options.annotation_collector = &annotation_collector;
|
||||
}
|
||||
|
||||
io::Printer p(output.get(), options);
|
||||
auto v = p.WithVars(CommonVars(file_options));
|
||||
|
||||
std::string info_path = absl::StrCat(basename, ".pb.h.meta");
|
||||
file_generator.GeneratePBHeader(
|
||||
&p, file_options.annotate_headers ? info_path : "");
|
||||
|
||||
if (file_options.annotate_headers) {
|
||||
auto info_output = absl::WrapUnique(generator_context->Open(info_path));
|
||||
annotations.SerializeToZeroCopyStream(info_output.get());
|
||||
}
|
||||
}
|
||||
|
||||
// Generate cc file(s).
|
||||
if (UsingImplicitWeakFields(file, file_options)) {
|
||||
{
|
||||
// This is the global .cc file, containing
|
||||
// enum/services/tables/reflection
|
||||
auto output = absl::WrapUnique(
|
||||
generator_context->Open(absl::StrCat(basename, ".pb.cc")));
|
||||
io::Printer p(output.get());
|
||||
auto v = p.WithVars(CommonVars(file_options));
|
||||
|
||||
file_generator.GenerateGlobalSource(&p);
|
||||
}
|
||||
|
||||
int num_cc_files =
|
||||
file_generator.NumMessages() + file_generator.NumExtensions();
|
||||
|
||||
// If we're using implicit weak fields then we allow the user to
|
||||
// optionally specify how many files to generate, not counting the global
|
||||
// pb.cc file. If we have more files than messages, then some files will
|
||||
// be generated as empty placeholders.
|
||||
if (file_options.num_cc_files > 0) {
|
||||
GOOGLE_CHECK_LE(num_cc_files, file_options.num_cc_files)
|
||||
<< "There must be at least as many numbered .cc files as messages "
|
||||
"and extensions.";
|
||||
num_cc_files = file_options.num_cc_files;
|
||||
}
|
||||
|
||||
int cc_file_number = 0;
|
||||
for (int i = 0; i < file_generator.NumMessages(); ++i) {
|
||||
auto output = absl::WrapUnique(generator_context->Open(
|
||||
NumberedCcFileName(basename, cc_file_number++)));
|
||||
io::Printer p(output.get());
|
||||
auto v = p.WithVars(CommonVars(file_options));
|
||||
|
||||
file_generator.GenerateSourceForMessage(i, &p);
|
||||
}
|
||||
|
||||
for (int i = 0; i < file_generator.NumExtensions(); ++i) {
|
||||
auto output = absl::WrapUnique(generator_context->Open(
|
||||
NumberedCcFileName(basename, cc_file_number++)));
|
||||
io::Printer p(output.get());
|
||||
auto v = p.WithVars(CommonVars(file_options));
|
||||
|
||||
file_generator.GenerateSourceForExtension(i, &p);
|
||||
}
|
||||
|
||||
// Create empty placeholder files if necessary to match the expected number
|
||||
// of files.
|
||||
while (cc_file_number < num_cc_files) {
|
||||
(void)absl::WrapUnique(generator_context->Open(
|
||||
NumberedCcFileName(basename, cc_file_number++)));
|
||||
}
|
||||
} else {
|
||||
auto output = absl::WrapUnique(
|
||||
generator_context->Open(absl::StrCat(basename, ".pb.cc")));
|
||||
io::Printer p(output.get());
|
||||
auto v = p.WithVars(CommonVars(file_options));
|
||||
|
||||
file_generator.GenerateSource(&p);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
105
libs/protobuf/src/google/protobuf/compiler/cpp/generator.h
Normal file
105
libs/protobuf/src/google/protobuf/compiler/cpp/generator.h
Normal file
@@ -0,0 +1,105 @@
|
||||
// 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.
|
||||
//
|
||||
// Generates C++ code for a given .proto file.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "google/protobuf/compiler/code_generator.h"
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
// CodeGenerator implementation which generates a C++ source file and
|
||||
// header. If you create your own protocol compiler binary and you want
|
||||
// it to support C++ output, you can do so by registering an instance of this
|
||||
// CodeGenerator with the CommandLineInterface in your main() function.
|
||||
class PROTOC_EXPORT CppGenerator : public CodeGenerator {
|
||||
public:
|
||||
CppGenerator() = default;
|
||||
CppGenerator(const CppGenerator&) = delete;
|
||||
CppGenerator& operator=(const CppGenerator&) = delete;
|
||||
~CppGenerator() override = default;
|
||||
|
||||
enum class Runtime {
|
||||
kGoogle3, // Use the internal google3 runtime.
|
||||
kOpensource, // Use the open-source runtime.
|
||||
|
||||
// Use the open-source runtime with google3 #include paths. We make these
|
||||
// absolute to avoid ambiguity, so the runtime will be #included like:
|
||||
// #include "third_party/protobuf/.../google/protobuf/message.h"
|
||||
kOpensourceGoogle3
|
||||
};
|
||||
|
||||
void set_opensource_runtime(bool opensource) {
|
||||
opensource_runtime_ = opensource;
|
||||
}
|
||||
|
||||
// If set to a non-empty string, generated code will do:
|
||||
// #include "<BASE>/google/protobuf/message.h"
|
||||
// instead of:
|
||||
// #include "google/protobuf/message.h"
|
||||
// This has no effect if opensource_runtime = false.
|
||||
void set_runtime_include_base(std::string base) {
|
||||
runtime_include_base_ = std::move(base);
|
||||
}
|
||||
|
||||
bool Generate(const FileDescriptor* file, const std::string& parameter,
|
||||
GeneratorContext* generator_context,
|
||||
std::string* error) const override;
|
||||
|
||||
uint64_t GetSupportedFeatures() const override {
|
||||
return FEATURE_PROTO3_OPTIONAL;
|
||||
}
|
||||
|
||||
private:
|
||||
bool opensource_runtime_ = PROTO2_IS_OSS;
|
||||
std::string runtime_include_base_;
|
||||
};
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__
|
||||
1626
libs/protobuf/src/google/protobuf/compiler/cpp/helpers.cc
Normal file
1626
libs/protobuf/src/google/protobuf/compiler/cpp/helpers.cc
Normal file
File diff suppressed because it is too large
Load Diff
1013
libs/protobuf/src/google/protobuf/compiler/cpp/helpers.h
Normal file
1013
libs/protobuf/src/google/protobuf/compiler/cpp/helpers.h
Normal file
File diff suppressed because it is too large
Load Diff
333
libs/protobuf/src/google/protobuf/compiler/cpp/map_field.cc
Normal file
333
libs/protobuf/src/google/protobuf/compiler/cpp/map_field.cc
Normal file
@@ -0,0 +1,333 @@
|
||||
// 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/compiler/cpp/map_field.h"
|
||||
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "google/protobuf/wire_format.h"
|
||||
#include "absl/strings/ascii.h"
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
|
||||
#include "google/protobuf/stubs/strutil.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
void SetMessageVariables(const FieldDescriptor* descriptor,
|
||||
std::map<std::string, std::string>* variables,
|
||||
const Options& options) {
|
||||
SetCommonFieldVariables(descriptor, variables, options);
|
||||
(*variables)["type"] = ClassName(descriptor->message_type(), false);
|
||||
(*variables)["full_name"] = descriptor->full_name();
|
||||
|
||||
const FieldDescriptor* key = descriptor->message_type()->map_key();
|
||||
const FieldDescriptor* val = descriptor->message_type()->map_value();
|
||||
(*variables)["key_cpp"] = PrimitiveTypeName(options, key->cpp_type());
|
||||
switch (val->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
(*variables)["val_cpp"] = FieldMessageTypeName(val, options);
|
||||
break;
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
(*variables)["val_cpp"] = ClassName(val->enum_type(), true);
|
||||
break;
|
||||
default:
|
||||
(*variables)["val_cpp"] = PrimitiveTypeName(options, val->cpp_type());
|
||||
}
|
||||
(*variables)["key_wire_type"] =
|
||||
"TYPE_" + absl::AsciiStrToUpper(DeclaredTypeMethodName(key->type()));
|
||||
(*variables)["val_wire_type"] =
|
||||
"TYPE_" + absl::AsciiStrToUpper(DeclaredTypeMethodName(val->type()));
|
||||
(*variables)["map_classname"] = ClassName(descriptor->message_type(), false);
|
||||
(*variables)["number"] = absl::StrCat(descriptor->number());
|
||||
(*variables)["tag"] = absl::StrCat(internal::WireFormat::MakeTag(descriptor));
|
||||
|
||||
if (HasDescriptorMethods(descriptor->file(), options)) {
|
||||
(*variables)["lite"] = "";
|
||||
} else {
|
||||
(*variables)["lite"] = "Lite";
|
||||
}
|
||||
}
|
||||
|
||||
MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer)
|
||||
: FieldGenerator(descriptor, options),
|
||||
has_required_fields_(
|
||||
scc_analyzer->HasRequiredFields(descriptor->message_type())) {
|
||||
SetMessageVariables(descriptor, &variables_, options);
|
||||
}
|
||||
|
||||
MapFieldGenerator::~MapFieldGenerator() {}
|
||||
|
||||
void MapFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"::$proto_ns$::internal::MapField$lite$<\n"
|
||||
" $map_classname$,\n"
|
||||
" $key_cpp$, $val_cpp$,\n"
|
||||
" ::$proto_ns$::internal::WireFormatLite::$key_wire_type$,\n"
|
||||
" ::$proto_ns$::internal::WireFormatLite::$val_wire_type$> "
|
||||
"$name$_;\n");
|
||||
}
|
||||
|
||||
void MapFieldGenerator::GenerateAccessorDeclarations(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"private:\n"
|
||||
"const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
|
||||
" ${1$_internal_$name$$}$() const;\n"
|
||||
"::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
|
||||
" ${1$_internal_mutable_$name$$}$();\n"
|
||||
"public:\n"
|
||||
"$deprecated_attr$const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
|
||||
" ${1$$name$$}$() const;\n"
|
||||
"$deprecated_attr$::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
|
||||
" ${1$mutable_$name$$}$();\n",
|
||||
descriptor_);
|
||||
}
|
||||
|
||||
void MapFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
|
||||
"$classname$::_internal_$name$() const {\n"
|
||||
" return $field$.GetMap();\n"
|
||||
"}\n"
|
||||
"inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
|
||||
"$classname$::$name$() const {\n"
|
||||
"$annotate_get$"
|
||||
" // @@protoc_insertion_point(field_map:$full_name$)\n"
|
||||
" return _internal_$name$();\n"
|
||||
"}\n"
|
||||
"inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
|
||||
"$classname$::_internal_mutable_$name$() {\n"
|
||||
"$maybe_prepare_split_message$"
|
||||
" return $field$.MutableMap();\n"
|
||||
"}\n"
|
||||
"inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
|
||||
"$classname$::mutable_$name$() {\n"
|
||||
"$annotate_mutable$"
|
||||
" // @@protoc_insertion_point(field_mutable_map:$full_name$)\n"
|
||||
" return _internal_mutable_$name$();\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void MapFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$.Clear();\n");
|
||||
}
|
||||
|
||||
void MapFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("_this->$field$.MergeFrom(from.$field$);\n");
|
||||
}
|
||||
|
||||
void MapFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$.InternalSwap(&other->$field$);\n");
|
||||
}
|
||||
|
||||
void MapFieldGenerator::GenerateCopyConstructorCode(
|
||||
io::Printer* printer) const {
|
||||
GenerateConstructorCode(printer);
|
||||
GenerateMergingCode(printer);
|
||||
}
|
||||
|
||||
static void GenerateSerializationLoop(Formatter& format, bool string_key,
|
||||
bool string_value,
|
||||
bool is_deterministic) {
|
||||
if (is_deterministic) {
|
||||
format(
|
||||
"for (const auto& entry : "
|
||||
"::_pbi::MapSorter$1$<MapType>(map_field)) {\n",
|
||||
(string_key ? "Ptr" : "Flat"));
|
||||
} else {
|
||||
format("for (const auto& entry : map_field) {\n");
|
||||
}
|
||||
{
|
||||
auto loop_scope = format.ScopedIndent();
|
||||
format(
|
||||
"target = WireHelper::InternalSerialize($number$, "
|
||||
"entry.first, entry.second, target, stream);\n");
|
||||
|
||||
if (string_key || string_value) {
|
||||
format("check_utf8(entry);\n");
|
||||
}
|
||||
}
|
||||
format("}\n");
|
||||
}
|
||||
|
||||
void MapFieldGenerator::GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("if (!this->_internal_$name$().empty()) {\n");
|
||||
format.Indent();
|
||||
const FieldDescriptor* key_field = descriptor_->message_type()->map_key();
|
||||
const FieldDescriptor* value_field = descriptor_->message_type()->map_value();
|
||||
const bool string_key = key_field->type() == FieldDescriptor::TYPE_STRING;
|
||||
const bool string_value = value_field->type() == FieldDescriptor::TYPE_STRING;
|
||||
|
||||
format(
|
||||
"using MapType = ::_pb::Map<$key_cpp$, $val_cpp$>;\n"
|
||||
"using WireHelper = $map_classname$::Funcs;\n"
|
||||
"const auto& map_field = this->_internal_$name$();\n");
|
||||
bool utf8_check = string_key || string_value;
|
||||
if (utf8_check) {
|
||||
format("auto check_utf8 = [](const MapType::value_type& entry) {\n");
|
||||
{
|
||||
auto check_scope = format.ScopedIndent();
|
||||
// p may be unused when GetUtf8CheckMode evaluates to kNone,
|
||||
// thus disabling the validation.
|
||||
format("(void)entry;\n");
|
||||
if (string_key) {
|
||||
GenerateUtf8CheckCodeForString(
|
||||
key_field, options_, false,
|
||||
"entry.first.data(), static_cast<int>(entry.first.length()),\n",
|
||||
format);
|
||||
}
|
||||
if (string_value) {
|
||||
GenerateUtf8CheckCodeForString(
|
||||
value_field, options_, false,
|
||||
"entry.second.data(), static_cast<int>(entry.second.length()),\n",
|
||||
format);
|
||||
}
|
||||
}
|
||||
format("};\n");
|
||||
}
|
||||
|
||||
format(
|
||||
"\n"
|
||||
"if (stream->IsSerializationDeterministic() && "
|
||||
"map_field.size() > 1) {\n");
|
||||
{
|
||||
auto deterministic_scope = format.ScopedIndent();
|
||||
GenerateSerializationLoop(format, string_key, string_value, true);
|
||||
}
|
||||
format("} else {\n");
|
||||
{
|
||||
auto map_order_scope = format.ScopedIndent();
|
||||
GenerateSerializationLoop(format, string_key, string_value, false);
|
||||
}
|
||||
format("}\n");
|
||||
format.Outdent();
|
||||
format("}\n");
|
||||
}
|
||||
|
||||
void MapFieldGenerator::GenerateByteSize(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"total_size += $tag_size$ *\n"
|
||||
" "
|
||||
"::$proto_ns$::internal::FromIntSize(this->_internal_$name$_size());\n"
|
||||
"for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
|
||||
" it = this->_internal_$name$().begin();\n"
|
||||
" it != this->_internal_$name$().end(); ++it) {\n"
|
||||
" total_size += $map_classname$::Funcs::ByteSizeLong(it->first, "
|
||||
"it->second);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void MapFieldGenerator::GenerateIsInitialized(io::Printer* printer) const {
|
||||
if (!has_required_fields_) return;
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"if (!::$proto_ns$::internal::AllAreInitialized($field$)) return "
|
||||
"false;\n");
|
||||
}
|
||||
|
||||
void MapFieldGenerator::GenerateConstexprAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (HasDescriptorMethods(descriptor_->file(), options_)) {
|
||||
format("/*decltype($field$)*/{::_pbi::ConstantInitialized()}");
|
||||
} else {
|
||||
format("/*decltype($field$)*/{}");
|
||||
}
|
||||
}
|
||||
|
||||
void MapFieldGenerator::GenerateCopyAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
// MapField has no move constructor, which prevents explicit aggregate
|
||||
// initialization pre-C++17.
|
||||
format("/*decltype($field$)*/{}");
|
||||
}
|
||||
|
||||
void MapFieldGenerator::GenerateAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format(
|
||||
"/*decltype($classname$::Split::$name$_)*/"
|
||||
"{::_pbi::ArenaInitialized(), arena}");
|
||||
return;
|
||||
}
|
||||
// MapField has no move constructor.
|
||||
format("/*decltype($field$)*/{::_pbi::ArenaInitialized(), arena}");
|
||||
}
|
||||
|
||||
void MapFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
|
||||
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("$cached_split_ptr$->$name$_.Destruct();\n");
|
||||
format("$cached_split_ptr$->$name$_.~MapField$lite$();\n");
|
||||
return;
|
||||
}
|
||||
format("$field$.Destruct();\n");
|
||||
format("$field$.~MapField$lite$();\n");
|
||||
}
|
||||
|
||||
void MapFieldGenerator::GenerateArenaDestructorCode(
|
||||
io::Printer* printer) const {
|
||||
if (NeedsArenaDestructor() == ArenaDtorNeeds::kNone) {
|
||||
return;
|
||||
}
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
// _this is the object being destructed (we are inside a static method here).
|
||||
format("_this->$field$.Destruct();\n");
|
||||
}
|
||||
|
||||
ArenaDtorNeeds MapFieldGenerator::NeedsArenaDestructor() const {
|
||||
return HasDescriptorMethods(descriptor_->file(), options_)
|
||||
? ArenaDtorNeeds::kRequired
|
||||
: ArenaDtorNeeds::kNone;
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
83
libs/protobuf/src/google/protobuf/compiler/cpp/map_field.h
Normal file
83
libs/protobuf/src/google/protobuf/compiler/cpp/map_field.h
Normal file
@@ -0,0 +1,83 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
#include "google/protobuf/compiler/cpp/message_field.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
class MapFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer);
|
||||
MapFieldGenerator(const MapFieldGenerator&) = delete;
|
||||
MapFieldGenerator& operator=(const MapFieldGenerator&) = delete;
|
||||
~MapFieldGenerator() override;
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const override;
|
||||
void GenerateAccessorDeclarations(io::Printer* printer) const override;
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
|
||||
void GenerateClearingCode(io::Printer* printer) const override;
|
||||
void GenerateMergingCode(io::Printer* printer) const override;
|
||||
void GenerateSwappingCode(io::Printer* printer) const override;
|
||||
void GenerateConstructorCode(io::Printer* printer) const override {}
|
||||
void GenerateCopyConstructorCode(io::Printer* printer) const override;
|
||||
void GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateByteSize(io::Printer* printer) const override;
|
||||
void GenerateIsInitialized(io::Printer* printer) const override;
|
||||
void GenerateConstexprAggregateInitializer(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateCopyAggregateInitializer(io::Printer* printer) const override;
|
||||
void GenerateAggregateInitializer(io::Printer* printer) const override;
|
||||
void GenerateDestructorCode(io::Printer* printer) const override;
|
||||
void GenerateArenaDestructorCode(io::Printer* printer) const override;
|
||||
ArenaDtorNeeds NeedsArenaDestructor() const override;
|
||||
|
||||
private:
|
||||
const bool has_required_fields_;
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__
|
||||
4461
libs/protobuf/src/google/protobuf/compiler/cpp/message.cc
Normal file
4461
libs/protobuf/src/google/protobuf/compiler/cpp/message.cc
Normal file
File diff suppressed because it is too large
Load Diff
226
libs/protobuf/src/google/protobuf/compiler/cpp/message.h
Normal file
226
libs/protobuf/src/google/protobuf/compiler/cpp/message.h
Normal file
@@ -0,0 +1,226 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "google/protobuf/compiler/cpp/enum.h"
|
||||
#include "google/protobuf/compiler/cpp/extension.h"
|
||||
#include "google/protobuf/compiler/cpp/field.h"
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
#include "google/protobuf/compiler/cpp/message_layout_helper.h"
|
||||
#include "google/protobuf/compiler/cpp/options.h"
|
||||
#include "google/protobuf/compiler/cpp/parse_function_generator.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
class MessageGenerator {
|
||||
public:
|
||||
MessageGenerator(const Descriptor* descriptor,
|
||||
const std::map<std::string, std::string>& ignored,
|
||||
int index_in_file_messages, const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer);
|
||||
|
||||
MessageGenerator(const MessageGenerator&) = delete;
|
||||
MessageGenerator& operator=(const MessageGenerator&) = delete;
|
||||
|
||||
~MessageGenerator() = default;
|
||||
|
||||
// Append the two types of nested generators to the corresponding vector.
|
||||
void AddGenerators(
|
||||
std::vector<std::unique_ptr<EnumGenerator>>* enum_generators,
|
||||
std::vector<std::unique_ptr<ExtensionGenerator>>* extension_generators);
|
||||
|
||||
// Generate definitions for this class and all its nested types.
|
||||
void GenerateClassDefinition(io::Printer* p);
|
||||
|
||||
// Generate definitions of inline methods (placed at the end of the header
|
||||
// file).
|
||||
void GenerateInlineMethods(io::Printer* p);
|
||||
|
||||
// Generate all non-inline methods for this class.
|
||||
void GenerateClassMethods(io::Printer* p);
|
||||
|
||||
// Generate source file code that should go outside any namespace.
|
||||
void GenerateSourceInProto2Namespace(io::Printer* p);
|
||||
|
||||
|
||||
void GenerateInitDefaultSplitInstance(io::Printer* p);
|
||||
|
||||
// Generate the constexpr constructor for constant initialization of the
|
||||
// default instance.
|
||||
void GenerateConstexprConstructor(io::Printer* p);
|
||||
|
||||
void GenerateSchema(io::Printer* p, int offset, int has_offset);
|
||||
|
||||
// Generate the field offsets array. Returns the a pair of the total number
|
||||
// of entries generated and the index of the first has_bit entry.
|
||||
std::pair<size_t, size_t> GenerateOffsets(io::Printer* p);
|
||||
|
||||
const Descriptor* descriptor() const { return descriptor_; }
|
||||
|
||||
private:
|
||||
// Generate declarations and definitions of accessors for fields.
|
||||
void GenerateFieldAccessorDeclarations(io::Printer* p);
|
||||
void GenerateFieldAccessorDefinitions(io::Printer* p);
|
||||
|
||||
// Generate constructors and destructor.
|
||||
void GenerateStructors(io::Printer* p);
|
||||
|
||||
// The compiler typically generates multiple copies of each constructor and
|
||||
// destructor: http://gcc.gnu.org/bugs.html#nonbugs_cxx
|
||||
// Placing common code in a separate method reduces the generated code size.
|
||||
//
|
||||
// Generate the shared constructor code.
|
||||
void GenerateSharedConstructorCode(io::Printer* p);
|
||||
// Generate the shared destructor code.
|
||||
void GenerateSharedDestructorCode(io::Printer* p);
|
||||
// Generate the arena-specific destructor code.
|
||||
void GenerateArenaDestructorCode(io::Printer* p);
|
||||
|
||||
// Generate standard Message methods.
|
||||
void GenerateClear(io::Printer* p);
|
||||
void GenerateOneofClear(io::Printer* p);
|
||||
void GenerateVerify(io::Printer* p);
|
||||
void GenerateSerializeWithCachedSizes(io::Printer* p);
|
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* p);
|
||||
void GenerateSerializeWithCachedSizesBody(io::Printer* p);
|
||||
void GenerateSerializeWithCachedSizesBodyShuffled(io::Printer* p);
|
||||
void GenerateByteSize(io::Printer* p);
|
||||
void GenerateMergeFrom(io::Printer* p);
|
||||
void GenerateClassSpecificMergeImpl(io::Printer* p);
|
||||
void GenerateCopyFrom(io::Printer* p);
|
||||
void GenerateSwap(io::Printer* p);
|
||||
void GenerateIsInitialized(io::Printer* p);
|
||||
|
||||
// Helpers for GenerateSerializeWithCachedSizes().
|
||||
//
|
||||
// cached_has_bit_index maintains that:
|
||||
// cached_has_bits = _has_bits_[cached_has_bit_index]
|
||||
// for cached_has_bit_index >= 0
|
||||
void GenerateSerializeOneField(io::Printer* p, const FieldDescriptor* field,
|
||||
int cached_has_bits_index);
|
||||
// Generate a switch statement to serialize 2+ fields from the same oneof.
|
||||
// Or, if fields.size() == 1, just call GenerateSerializeOneField().
|
||||
void GenerateSerializeOneofFields(
|
||||
io::Printer* p, const std::vector<const FieldDescriptor*>& fields);
|
||||
void GenerateSerializeOneExtensionRange(
|
||||
io::Printer* p, const Descriptor::ExtensionRange* range);
|
||||
|
||||
// Generates has_foo() functions and variables for singular field has-bits.
|
||||
void GenerateSingularFieldHasBits(const FieldDescriptor* field,
|
||||
io::Printer* p);
|
||||
// Generates has_foo() functions and variables for oneof field has-bits.
|
||||
void GenerateOneofHasBits(io::Printer* p);
|
||||
// Generates has_foo_bar() functions for oneof members.
|
||||
void GenerateOneofMemberHasBits(const FieldDescriptor* field, io::Printer* p);
|
||||
// Generates the clear_foo() method for a field.
|
||||
void GenerateFieldClear(const FieldDescriptor* field, bool is_inline,
|
||||
io::Printer* p);
|
||||
|
||||
// Generates the body of the message's copy constructor.
|
||||
void GenerateCopyConstructorBody(io::Printer* p) const;
|
||||
|
||||
// Returns the level that this message needs ArenaDtor. If the message has
|
||||
// a field that is not arena-exclusive, it needs an ArenaDtor
|
||||
// (go/proto-destructor).
|
||||
//
|
||||
// - Returning kNone means we don't need to generate ArenaDtor.
|
||||
// - Returning kOnDemand means we need to generate ArenaDtor, but don't need
|
||||
// to register ArenaDtor at construction. Such as when the message's
|
||||
// ArenaDtor code is only for destructing inlined string.
|
||||
// - Returning kRequired means we meed to generate ArenaDtor and register it
|
||||
// at construction.
|
||||
ArenaDtorNeeds NeedsArenaDestructor() const;
|
||||
|
||||
size_t HasBitsSize() const;
|
||||
size_t InlinedStringDonatedSize() const;
|
||||
int HasBitIndex(const FieldDescriptor* field) const;
|
||||
int HasByteIndex(const FieldDescriptor* field) const;
|
||||
int HasWordIndex(const FieldDescriptor* field) const;
|
||||
std::vector<uint32_t> RequiredFieldsBitMask() const;
|
||||
|
||||
const Descriptor* descriptor_;
|
||||
int index_in_file_messages_;
|
||||
Options options_;
|
||||
FieldGeneratorMap field_generators_;
|
||||
// optimized_order_ is the order we layout the message's fields in the
|
||||
// class. This is reused to initialize the fields in-order for cache
|
||||
// efficiency.
|
||||
//
|
||||
// optimized_order_ excludes oneof fields and weak fields.
|
||||
std::vector<const FieldDescriptor*> optimized_order_;
|
||||
std::vector<int> has_bit_indices_;
|
||||
int max_has_bit_index_ = 0;
|
||||
|
||||
// A map from field index to inlined_string index. For non-inlined-string
|
||||
// fields, the element is -1. If there is no inlined string in the message,
|
||||
// this is empty.
|
||||
std::vector<int> inlined_string_indices_;
|
||||
// The count of inlined_string fields in the message.
|
||||
int max_inlined_string_index_ = 0;
|
||||
|
||||
std::vector<const EnumGenerator*> enum_generators_;
|
||||
std::vector<const ExtensionGenerator*> extension_generators_;
|
||||
int num_required_fields_ = 0;
|
||||
int num_weak_fields_ = 0;
|
||||
|
||||
std::unique_ptr<MessageLayoutHelper> message_layout_helper_;
|
||||
std::unique_ptr<ParseFunctionGenerator> parse_function_generator_;
|
||||
|
||||
MessageSCCAnalyzer* scc_analyzer_;
|
||||
|
||||
std::map<std::string, std::string> variables_;
|
||||
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
|
||||
965
libs/protobuf/src/google/protobuf/compiler/cpp/message_field.cc
Normal file
965
libs/protobuf/src/google/protobuf/compiler/cpp/message_field.cc
Normal file
@@ -0,0 +1,965 @@
|
||||
// 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/compiler/cpp/message_field.h"
|
||||
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "google/protobuf/compiler/cpp/field.h"
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
|
||||
#include "google/protobuf/stubs/strutil.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
namespace {
|
||||
std::string ReinterpretCast(const std::string& type,
|
||||
const std::string& expression,
|
||||
bool implicit_weak_field) {
|
||||
if (implicit_weak_field) {
|
||||
return "reinterpret_cast< " + type + " >(" + expression + ")";
|
||||
} else {
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
|
||||
void SetMessageVariables(const FieldDescriptor* descriptor,
|
||||
const Options& options, bool implicit_weak,
|
||||
std::map<std::string, std::string>* variables) {
|
||||
SetCommonFieldVariables(descriptor, variables, options);
|
||||
(*variables)["type"] = FieldMessageTypeName(descriptor, options);
|
||||
(*variables)["casted_member"] = ReinterpretCast(
|
||||
(*variables)["type"] + "*", (*variables)["field"], implicit_weak);
|
||||
(*variables)["casted_member_const"] =
|
||||
ReinterpretCast("const " + (*variables)["type"] + "&",
|
||||
"*" + (*variables)["field"], implicit_weak);
|
||||
(*variables)["type_default_instance"] =
|
||||
QualifiedDefaultInstanceName(descriptor->message_type(), options);
|
||||
(*variables)["type_default_instance_ptr"] = ReinterpretCast(
|
||||
"const ::PROTOBUF_NAMESPACE_ID::MessageLite*",
|
||||
QualifiedDefaultInstancePtr(descriptor->message_type(), options),
|
||||
implicit_weak);
|
||||
(*variables)["type_reference_function"] =
|
||||
implicit_weak ? (" ::" + ProtobufNamespace(options) +
|
||||
"::internal::StrongReference(reinterpret_cast<const " +
|
||||
(*variables)["type"] + "&>(\n" +
|
||||
(*variables)["type_default_instance"] + "));\n")
|
||||
: "";
|
||||
// NOTE: Escaped here to unblock proto1->proto2 migration.
|
||||
// TODO(liujisi): Extend this to apply for other conflicting methods.
|
||||
(*variables)["release_name"] =
|
||||
SafeFunctionName(descriptor->containing_type(), descriptor, "release_");
|
||||
(*variables)["full_name"] = descriptor->full_name();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer)
|
||||
: FieldGenerator(descriptor, options),
|
||||
implicit_weak_field_(
|
||||
IsImplicitWeakField(descriptor, options, scc_analyzer)),
|
||||
has_required_fields_(
|
||||
scc_analyzer->HasRequiredFields(descriptor->message_type())) {
|
||||
SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_);
|
||||
}
|
||||
|
||||
MessageFieldGenerator::~MessageFieldGenerator() {}
|
||||
|
||||
void MessageFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (implicit_weak_field_) {
|
||||
format("::$proto_ns$::MessageLite* $name$_;\n");
|
||||
} else {
|
||||
format("$type$* $name$_;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::GenerateAccessorDeclarations(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (IsFieldStripped(descriptor_, options_)) {
|
||||
format(
|
||||
"$deprecated_attr$const $type$& ${1$$name$$}$() const { "
|
||||
"__builtin_trap(); }\n"
|
||||
"PROTOBUF_NODISCARD $deprecated_attr$$type$* "
|
||||
"${1$$release_name$$}$() { "
|
||||
"__builtin_trap(); }\n"
|
||||
"$deprecated_attr$$type$* ${1$mutable_$name$$}$() { "
|
||||
"__builtin_trap(); }\n"
|
||||
"$deprecated_attr$void ${1$set_allocated_$name$$}$"
|
||||
"($type$* $name$) { __builtin_trap(); }\n"
|
||||
"$deprecated_attr$void "
|
||||
"${1$unsafe_arena_set_allocated_$name$$}$(\n"
|
||||
" $type$* $name$) { __builtin_trap(); }\n"
|
||||
"$deprecated_attr$$type$* ${1$unsafe_arena_release_$name$$}$() { "
|
||||
"__builtin_trap(); }\n",
|
||||
descriptor_);
|
||||
return;
|
||||
}
|
||||
format(
|
||||
"$deprecated_attr$const $type$& ${1$$name$$}$() const;\n"
|
||||
"PROTOBUF_NODISCARD $deprecated_attr$$type$* "
|
||||
"${1$$release_name$$}$();\n"
|
||||
"$deprecated_attr$$type$* ${1$mutable_$name$$}$();\n"
|
||||
"$deprecated_attr$void ${1$set_allocated_$name$$}$"
|
||||
"($type$* $name$);\n",
|
||||
descriptor_);
|
||||
if (!IsFieldStripped(descriptor_, options_)) {
|
||||
format(
|
||||
"private:\n"
|
||||
"const $type$& ${1$_internal_$name$$}$() const;\n"
|
||||
"$type$* ${1$_internal_mutable_$name$$}$();\n"
|
||||
"public:\n",
|
||||
descriptor_);
|
||||
}
|
||||
format(
|
||||
"$deprecated_attr$void "
|
||||
"${1$unsafe_arena_set_allocated_$name$$}$(\n"
|
||||
" $type$* $name$);\n"
|
||||
"$deprecated_attr$$type$* ${1$unsafe_arena_release_$name$$}$();\n",
|
||||
descriptor_);
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
|
||||
io::Printer* printer) const {}
|
||||
|
||||
void MessageFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"inline const $type$& $classname$::_internal_$name$() const {\n"
|
||||
"$type_reference_function$"
|
||||
" const $type$* p = $casted_member$;\n"
|
||||
" return p != nullptr ? *p : reinterpret_cast<const $type$&>(\n"
|
||||
" $type_default_instance$);\n"
|
||||
"}\n"
|
||||
"inline const $type$& $classname$::$name$() const {\n"
|
||||
"$annotate_get$"
|
||||
" // @@protoc_insertion_point(field_get:$full_name$)\n"
|
||||
" return _internal_$name$();\n"
|
||||
"}\n");
|
||||
|
||||
format(
|
||||
"inline void $classname$::unsafe_arena_set_allocated_$name$(\n"
|
||||
" $type$* $name$) {\n"
|
||||
"$maybe_prepare_split_message$"
|
||||
// If we're not on an arena, free whatever we were holding before.
|
||||
// (If we are on arena, we can just forget the earlier pointer.)
|
||||
" if (GetArenaForAllocation() == nullptr) {\n"
|
||||
" delete reinterpret_cast<::$proto_ns$::MessageLite*>($field$);\n"
|
||||
" }\n");
|
||||
if (implicit_weak_field_) {
|
||||
format(
|
||||
" $field$ = reinterpret_cast<::$proto_ns$::MessageLite*>($name$);\n");
|
||||
} else {
|
||||
format(" $field$ = $name$;\n");
|
||||
}
|
||||
auto nonempty = [this](const char* fn) {
|
||||
auto var_it = variables_.find(fn);
|
||||
return var_it != variables_.end() && !var_it->second.empty();
|
||||
};
|
||||
if (nonempty("set_hasbit") || nonempty("clear_hasbit")) {
|
||||
format(
|
||||
" if ($name$) {\n"
|
||||
" $set_hasbit$\n"
|
||||
" } else {\n"
|
||||
" $clear_hasbit$\n"
|
||||
" }\n");
|
||||
}
|
||||
format(
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_unsafe_arena_set_allocated"
|
||||
":$full_name$)\n"
|
||||
"}\n");
|
||||
format(
|
||||
"inline $type$* $classname$::$release_name$() {\n"
|
||||
"$type_reference_function$"
|
||||
"$annotate_release$"
|
||||
"$maybe_prepare_split_message$"
|
||||
" $clear_hasbit$\n"
|
||||
" $type$* temp = $casted_member$;\n"
|
||||
" $field$ = nullptr;\n"
|
||||
"#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE\n"
|
||||
" auto* old = reinterpret_cast<::$proto_ns$::MessageLite*>(temp);\n"
|
||||
" temp = ::$proto_ns$::internal::DuplicateIfNonNull(temp);\n"
|
||||
" if (GetArenaForAllocation() == nullptr) { delete old; }\n"
|
||||
"#else // PROTOBUF_FORCE_COPY_IN_RELEASE\n"
|
||||
" if (GetArenaForAllocation() != nullptr) {\n"
|
||||
" temp = ::$proto_ns$::internal::DuplicateIfNonNull(temp);\n"
|
||||
" }\n"
|
||||
"#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE\n"
|
||||
" return temp;\n"
|
||||
"}\n"
|
||||
"inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
|
||||
"$annotate_release$"
|
||||
" // @@protoc_insertion_point(field_release:$full_name$)\n"
|
||||
"$type_reference_function$"
|
||||
"$maybe_prepare_split_message$"
|
||||
" $clear_hasbit$\n"
|
||||
" $type$* temp = $casted_member$;\n"
|
||||
" $field$ = nullptr;\n"
|
||||
" return temp;\n"
|
||||
"}\n");
|
||||
|
||||
format(
|
||||
"inline $type$* $classname$::_internal_mutable_$name$() {\n"
|
||||
"$type_reference_function$"
|
||||
" $set_hasbit$\n"
|
||||
" if ($field$ == nullptr) {\n"
|
||||
" auto* p = CreateMaybeMessage<$type$>(GetArenaForAllocation());\n");
|
||||
if (implicit_weak_field_) {
|
||||
format(" $field$ = reinterpret_cast<::$proto_ns$::MessageLite*>(p);\n");
|
||||
} else {
|
||||
format(" $field$ = p;\n");
|
||||
}
|
||||
format(
|
||||
" }\n"
|
||||
" return $casted_member$;\n"
|
||||
"}\n"
|
||||
"inline $type$* $classname$::mutable_$name$() {\n"
|
||||
// TODO(b/122856539): add tests to make sure all write accessors are able
|
||||
// to prepare split message allocation.
|
||||
"$maybe_prepare_split_message$"
|
||||
" $type$* _msg = _internal_mutable_$name$();\n"
|
||||
"$annotate_mutable$"
|
||||
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
|
||||
" return _msg;\n"
|
||||
"}\n");
|
||||
|
||||
// We handle the most common case inline, and delegate less common cases to
|
||||
// the slow fallback function.
|
||||
format(
|
||||
"inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
|
||||
" ::$proto_ns$::Arena* message_arena = GetArenaForAllocation();\n");
|
||||
format(
|
||||
"$maybe_prepare_split_message$"
|
||||
" if (message_arena == nullptr) {\n");
|
||||
if (IsCrossFileMessage(descriptor_)) {
|
||||
format(
|
||||
" delete reinterpret_cast< ::$proto_ns$::MessageLite*>($field$);\n");
|
||||
} else {
|
||||
format(" delete $field$;\n");
|
||||
}
|
||||
format(
|
||||
" }\n"
|
||||
" if ($name$) {\n");
|
||||
if (IsCrossFileMessage(descriptor_)) {
|
||||
// We have to read the arena through the virtual method, because the type
|
||||
// isn't defined in this file.
|
||||
format(
|
||||
" ::$proto_ns$::Arena* submessage_arena =\n"
|
||||
" ::$proto_ns$::Arena::InternalGetOwningArena(\n"
|
||||
" reinterpret_cast<::$proto_ns$::MessageLite*>("
|
||||
"$name$));\n");
|
||||
} else {
|
||||
format(
|
||||
" ::$proto_ns$::Arena* submessage_arena =\n"
|
||||
" ::$proto_ns$::Arena::InternalGetOwningArena("
|
||||
"$name$);\n");
|
||||
}
|
||||
format(
|
||||
" if (message_arena != submessage_arena) {\n"
|
||||
" $name$ = ::$proto_ns$::internal::GetOwnedMessage(\n"
|
||||
" message_arena, $name$, submessage_arena);\n"
|
||||
" }\n"
|
||||
" $set_hasbit$\n"
|
||||
" } else {\n"
|
||||
" $clear_hasbit$\n"
|
||||
" }\n");
|
||||
if (implicit_weak_field_) {
|
||||
format(" $field$ = reinterpret_cast<MessageLite*>($name$);\n");
|
||||
} else {
|
||||
format(" $field$ = $name$;\n");
|
||||
}
|
||||
format(
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::GenerateInternalAccessorDeclarations(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (implicit_weak_field_) {
|
||||
format(
|
||||
"static const ::$proto_ns$::MessageLite& $name$("
|
||||
"const $classname$* msg);\n"
|
||||
"static ::$proto_ns$::MessageLite* mutable_$name$("
|
||||
"$classname$* msg);\n");
|
||||
} else {
|
||||
format("static const $type$& $name$(const $classname$* msg);\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::GenerateInternalAccessorDefinitions(
|
||||
io::Printer* printer) const {
|
||||
// In theory, these accessors could be inline in _Internal. However, in
|
||||
// practice, the linker is then not able to throw them out making implicit
|
||||
// weak dependencies not work at all.
|
||||
Formatter format(printer, variables_);
|
||||
if (implicit_weak_field_) {
|
||||
// These private accessors are used by MergeFrom and
|
||||
// MergePartialFromCodedStream, and their purpose is to provide access to
|
||||
// the field without creating a strong dependency on the message type.
|
||||
format(
|
||||
"const ::$proto_ns$::MessageLite& $classname$::_Internal::$name$(\n"
|
||||
" const $classname$* msg) {\n"
|
||||
" if (msg->$field$ != nullptr) {\n"
|
||||
" return *msg->$field$;\n"
|
||||
" } else {\n"
|
||||
" return *$type_default_instance_ptr$;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
format(
|
||||
"::$proto_ns$::MessageLite*\n"
|
||||
"$classname$::_Internal::mutable_$name$($classname$* msg) {\n");
|
||||
if (internal::cpp::HasHasbit(descriptor_)) {
|
||||
format(" msg->$set_hasbit$\n");
|
||||
}
|
||||
if (descriptor_->real_containing_oneof() == nullptr) {
|
||||
format(" if (msg->$field$ == nullptr) {\n");
|
||||
} else {
|
||||
format(
|
||||
" if (!msg->_internal_has_$name$()) {\n"
|
||||
" msg->clear_$oneof_name$();\n"
|
||||
" msg->set_has_$name$();\n");
|
||||
}
|
||||
format(
|
||||
" msg->$field$ = $type_default_instance_ptr$->New(\n"
|
||||
" msg->GetArenaForAllocation());\n"
|
||||
" }\n"
|
||||
" return msg->$field$;\n"
|
||||
"}\n");
|
||||
} else {
|
||||
// This inline accessor directly returns member field and is used in
|
||||
// Serialize such that AFDO profile correctly captures access information to
|
||||
// message fields under serialize.
|
||||
format(
|
||||
"const $type$&\n"
|
||||
"$classname$::_Internal::$name$(const $classname$* msg) {\n"
|
||||
" return *msg->$field$;\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
|
||||
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
if (!internal::cpp::HasHasbit(descriptor_)) {
|
||||
// If we don't have has-bits, message presence is indicated only by ptr !=
|
||||
// nullptr. Thus on clear, we need to delete the object.
|
||||
format(
|
||||
"if (GetArenaForAllocation() == nullptr && $field$ != nullptr) {\n"
|
||||
" delete $field$;\n"
|
||||
"}\n"
|
||||
"$field$ = nullptr;\n");
|
||||
} else {
|
||||
format("if ($field$ != nullptr) $field$->Clear();\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::GenerateMessageClearingCode(
|
||||
io::Printer* printer) const {
|
||||
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
if (!internal::cpp::HasHasbit(descriptor_)) {
|
||||
// If we don't have has-bits, message presence is indicated only by ptr !=
|
||||
// nullptr. Thus on clear, we need to delete the object.
|
||||
format(
|
||||
"if (GetArenaForAllocation() == nullptr && $field$ != nullptr) {\n"
|
||||
" delete $field$;\n"
|
||||
"}\n"
|
||||
"$field$ = nullptr;\n");
|
||||
} else {
|
||||
format(
|
||||
"$DCHK$($field$ != nullptr);\n"
|
||||
"$field$->Clear();\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
|
||||
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
if (implicit_weak_field_) {
|
||||
format(
|
||||
"_Internal::mutable_$name$(_this)->CheckTypeAndMergeFrom(\n"
|
||||
" _Internal::$name$(&from));\n");
|
||||
} else {
|
||||
format(
|
||||
"_this->_internal_mutable_$name$()->$type$::MergeFrom(\n"
|
||||
" from._internal_$name$());\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
|
||||
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
format("swap($field$, other->$field$);\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
|
||||
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
if (options_.opensource_runtime) {
|
||||
// TODO(gerbens) Remove this when we don't need to destruct default
|
||||
// instances. In google3 a default instance will never get deleted so we
|
||||
// don't need to worry about that but in opensource protobuf default
|
||||
// instances are deleted in shutdown process and we need to take special
|
||||
// care when handling them.
|
||||
format("if (this != internal_default_instance()) ");
|
||||
}
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("delete $cached_split_ptr$->$name$_;\n");
|
||||
return;
|
||||
}
|
||||
format("delete $field$;\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::GenerateCopyConstructorCode(
|
||||
io::Printer* printer) const {
|
||||
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"if (from._internal_has_$name$()) {\n"
|
||||
" _this->$field$ = new $type$(*from.$field$);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const {
|
||||
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
|
||||
format(
|
||||
"target = ::$proto_ns$::internal::WireFormatLite::\n"
|
||||
" InternalWrite$declared_type$($number$, _Internal::$name$(this),\n"
|
||||
" _Internal::$name$(this).GetCachedSize(), target, stream);\n");
|
||||
} else {
|
||||
format(
|
||||
"target = stream->EnsureSpace(target);\n"
|
||||
"target = ::$proto_ns$::internal::WireFormatLite::\n"
|
||||
" InternalWrite$declared_type$(\n"
|
||||
" $number$, _Internal::$name$(this), target, stream);\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::GenerateByteSize(io::Printer* printer) const {
|
||||
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"total_size += $tag_size$ +\n"
|
||||
" ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n"
|
||||
" *$field$);\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 (!$field$->IsInitialized()) return false;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::GenerateConstexprAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("/*decltype($field$)*/nullptr");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::GenerateCopyAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("decltype($field$){nullptr}");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::GenerateAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("decltype(Impl_::Split::$name$_){nullptr}");
|
||||
return;
|
||||
}
|
||||
format("decltype($field$){nullptr}");
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
MessageOneofFieldGenerator::MessageOneofFieldGenerator(
|
||||
const FieldDescriptor* descriptor, const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer)
|
||||
: MessageFieldGenerator(descriptor, options, scc_analyzer) {
|
||||
SetCommonOneofFieldVariables(descriptor, &variables_);
|
||||
}
|
||||
|
||||
MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {}
|
||||
|
||||
void MessageOneofFieldGenerator::GenerateNonInlineAccessorDefinitions(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"void $classname$::set_allocated_$name$($type$* $name$) {\n"
|
||||
" ::$proto_ns$::Arena* message_arena = GetArenaForAllocation();\n"
|
||||
" clear_$oneof_name$();\n"
|
||||
" if ($name$) {\n");
|
||||
if (descriptor_->file() != descriptor_->message_type()->file()) {
|
||||
// We have to read the arena through the virtual method, because the type
|
||||
// isn't defined in this file.
|
||||
format(
|
||||
" ::$proto_ns$::Arena* submessage_arena =\n"
|
||||
" ::$proto_ns$::Arena::InternalGetOwningArena(\n"
|
||||
" reinterpret_cast<::$proto_ns$::MessageLite*>("
|
||||
"$name$));\n");
|
||||
} else {
|
||||
format(
|
||||
" ::$proto_ns$::Arena* submessage_arena =\n"
|
||||
" ::$proto_ns$::Arena::InternalGetOwningArena($name$);\n");
|
||||
}
|
||||
format(
|
||||
" if (message_arena != submessage_arena) {\n"
|
||||
" $name$ = ::$proto_ns$::internal::GetOwnedMessage(\n"
|
||||
" message_arena, $name$, submessage_arena);\n"
|
||||
" }\n"
|
||||
" set_has_$name$();\n"
|
||||
" $field$ = $name$;\n"
|
||||
" }\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void MessageOneofFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"inline $type$* $classname$::$release_name$() {\n"
|
||||
"$annotate_release$"
|
||||
" // @@protoc_insertion_point(field_release:$full_name$)\n"
|
||||
"$type_reference_function$"
|
||||
" if (_internal_has_$name$()) {\n"
|
||||
" clear_has_$oneof_name$();\n"
|
||||
" $type$* temp = $casted_member$;\n"
|
||||
" if (GetArenaForAllocation() != nullptr) {\n"
|
||||
" temp = ::$proto_ns$::internal::DuplicateIfNonNull(temp);\n"
|
||||
" }\n"
|
||||
" $field$ = nullptr;\n"
|
||||
" return temp;\n"
|
||||
" } else {\n"
|
||||
" return nullptr;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
|
||||
format(
|
||||
"inline const $type$& $classname$::_internal_$name$() const {\n"
|
||||
"$type_reference_function$"
|
||||
" return _internal_has_$name$()\n"
|
||||
" ? $casted_member_const$\n"
|
||||
" : reinterpret_cast< $type$&>($type_default_instance$);\n"
|
||||
"}\n"
|
||||
"inline const $type$& $classname$::$name$() const {\n"
|
||||
"$annotate_get$"
|
||||
" // @@protoc_insertion_point(field_get:$full_name$)\n"
|
||||
" return _internal_$name$();\n"
|
||||
"}\n"
|
||||
"inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
|
||||
"$annotate_release$"
|
||||
" // @@protoc_insertion_point(field_unsafe_arena_release"
|
||||
":$full_name$)\n"
|
||||
"$type_reference_function$"
|
||||
" if (_internal_has_$name$()) {\n"
|
||||
" clear_has_$oneof_name$();\n"
|
||||
" $type$* temp = $casted_member$;\n"
|
||||
" $field$ = nullptr;\n"
|
||||
" return temp;\n"
|
||||
" } else {\n"
|
||||
" return nullptr;\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"inline void $classname$::unsafe_arena_set_allocated_$name$"
|
||||
"($type$* $name$) {\n"
|
||||
// We rely on the oneof clear method to free the earlier contents of
|
||||
// this oneof. We can directly use the pointer we're given to set the
|
||||
// new value.
|
||||
" clear_$oneof_name$();\n"
|
||||
" if ($name$) {\n"
|
||||
" set_has_$name$();\n");
|
||||
if (implicit_weak_field_) {
|
||||
format(
|
||||
" $field$ = "
|
||||
"reinterpret_cast<::$proto_ns$::MessageLite*>($name$);\n");
|
||||
} else {
|
||||
format(" $field$ = $name$;\n");
|
||||
}
|
||||
format(
|
||||
" }\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_unsafe_arena_set_allocated:"
|
||||
"$full_name$)\n"
|
||||
"}\n"
|
||||
"inline $type$* $classname$::_internal_mutable_$name$() {\n"
|
||||
"$type_reference_function$"
|
||||
" if (!_internal_has_$name$()) {\n"
|
||||
" clear_$oneof_name$();\n"
|
||||
" set_has_$name$();\n");
|
||||
if (implicit_weak_field_) {
|
||||
format(
|
||||
" $field$ = "
|
||||
"reinterpret_cast<::$proto_ns$::MessageLite*>(CreateMaybeMessage< "
|
||||
"$type$ >(GetArenaForAllocation()));\n");
|
||||
} else {
|
||||
format(
|
||||
" $field$ = CreateMaybeMessage< $type$ "
|
||||
">(GetArenaForAllocation());\n");
|
||||
}
|
||||
format(
|
||||
" }\n"
|
||||
" return $casted_member$;\n"
|
||||
"}\n"
|
||||
"inline $type$* $classname$::mutable_$name$() {\n"
|
||||
" $type$* _msg = _internal_mutable_$name$();\n"
|
||||
"$annotate_mutable$"
|
||||
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
|
||||
" return _msg;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void MessageOneofFieldGenerator::GenerateClearingCode(
|
||||
io::Printer* printer) const {
|
||||
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"if (GetArenaForAllocation() == nullptr) {\n"
|
||||
" delete $field$;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void MessageOneofFieldGenerator::GenerateMessageClearingCode(
|
||||
io::Printer* printer) const {
|
||||
GenerateClearingCode(printer);
|
||||
}
|
||||
|
||||
void MessageOneofFieldGenerator::GenerateSwappingCode(
|
||||
io::Printer* printer) const {
|
||||
// Don't print any swapping code. Swapping the union will swap this field.
|
||||
}
|
||||
|
||||
void MessageOneofFieldGenerator::GenerateDestructorCode(
|
||||
io::Printer* printer) const {
|
||||
// We inherit from MessageFieldGenerator, so we need to override the default
|
||||
// behavior.
|
||||
}
|
||||
|
||||
void MessageOneofFieldGenerator::GenerateConstructorCode(
|
||||
io::Printer* printer) const {
|
||||
// Don't print any constructor code. The field is in a union. We allocate
|
||||
// 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$->IsInitialized()) return false;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
|
||||
const FieldDescriptor* descriptor, const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer)
|
||||
: FieldGenerator(descriptor, options),
|
||||
implicit_weak_field_(
|
||||
IsImplicitWeakField(descriptor, options, scc_analyzer)),
|
||||
has_required_fields_(
|
||||
scc_analyzer->HasRequiredFields(descriptor->message_type())) {
|
||||
SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_);
|
||||
}
|
||||
|
||||
RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
|
||||
|
||||
void RepeatedMessageFieldGenerator::GeneratePrivateMembers(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (implicit_weak_field_) {
|
||||
format("::$proto_ns$::WeakRepeatedPtrField< $type$ > $name$_;\n");
|
||||
} else {
|
||||
format("::$proto_ns$::RepeatedPtrField< $type$ > $name$_;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::GenerateAccessorDeclarations(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (IsFieldStripped(descriptor_, options_)) {
|
||||
format(
|
||||
"$deprecated_attr$$type$* ${1$mutable_$name$$}$(int index) { "
|
||||
"__builtin_trap(); }\n"
|
||||
"$deprecated_attr$::$proto_ns$::RepeatedPtrField< $type$ >*\n"
|
||||
" ${1$mutable_$name$$}$() { __builtin_trap(); }\n"
|
||||
"$deprecated_attr$const $type$& ${1$$name$$}$(int index) const { "
|
||||
"__builtin_trap(); }\n"
|
||||
"$deprecated_attr$$type$* ${1$add_$name$$}$() { "
|
||||
"__builtin_trap(); }\n"
|
||||
"$deprecated_attr$const ::$proto_ns$::RepeatedPtrField< $type$ >&\n"
|
||||
" ${1$$name$$}$() const { __builtin_trap(); }\n",
|
||||
descriptor_);
|
||||
return;
|
||||
}
|
||||
format(
|
||||
"$deprecated_attr$$type$* ${1$mutable_$name$$}$(int index);\n"
|
||||
"$deprecated_attr$::$proto_ns$::RepeatedPtrField< $type$ >*\n"
|
||||
" ${1$mutable_$name$$}$();\n",
|
||||
descriptor_);
|
||||
if (!IsFieldStripped(descriptor_, options_)) {
|
||||
format(
|
||||
"private:\n"
|
||||
"const $type$& ${1$_internal_$name$$}$(int index) const;\n"
|
||||
"$type$* ${1$_internal_add_$name$$}$();\n"
|
||||
"public:\n",
|
||||
descriptor_);
|
||||
}
|
||||
format(
|
||||
"$deprecated_attr$const $type$& ${1$$name$$}$(int index) const;\n"
|
||||
"$deprecated_attr$$type$* ${1$add_$name$$}$();\n"
|
||||
"$deprecated_attr$const ::$proto_ns$::RepeatedPtrField< $type$ >&\n"
|
||||
" ${1$$name$$}$() const;\n",
|
||||
descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format.Set("weak", implicit_weak_field_ ? ".weak" : "");
|
||||
|
||||
format(
|
||||
"inline $type$* $classname$::mutable_$name$(int index) {\n"
|
||||
"$annotate_mutable$"
|
||||
// TODO(dlj): move insertion points
|
||||
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
|
||||
"$type_reference_function$"
|
||||
" return $field$$weak$.Mutable(index);\n"
|
||||
"}\n"
|
||||
"inline ::$proto_ns$::RepeatedPtrField< $type$ >*\n"
|
||||
"$classname$::mutable_$name$() {\n"
|
||||
"$annotate_mutable_list$"
|
||||
" // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
|
||||
"$type_reference_function$"
|
||||
" return &$field$$weak$;\n"
|
||||
"}\n");
|
||||
|
||||
if (options_.safe_boundary_check) {
|
||||
format(
|
||||
"inline const $type$& $classname$::_internal_$name$(int index) const "
|
||||
"{\n"
|
||||
" return $field$$weak$.InternalCheckedGet(index,\n"
|
||||
" reinterpret_cast<const $type$&>($type_default_instance$));\n"
|
||||
"}\n");
|
||||
} else {
|
||||
format(
|
||||
"inline const $type$& $classname$::_internal_$name$(int index) const "
|
||||
"{\n"
|
||||
"$type_reference_function$"
|
||||
" return $field$$weak$.Get(index);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
format(
|
||||
"inline const $type$& $classname$::$name$(int index) const {\n"
|
||||
"$annotate_get$"
|
||||
" // @@protoc_insertion_point(field_get:$full_name$)\n"
|
||||
" return _internal_$name$(index);\n"
|
||||
"}\n"
|
||||
"inline $type$* $classname$::_internal_add_$name$() {\n"
|
||||
" return $field$$weak$.Add();\n"
|
||||
"}\n"
|
||||
"inline $type$* $classname$::add_$name$() {\n"
|
||||
" $type$* _add = _internal_add_$name$();\n"
|
||||
"$annotate_add_mutable$"
|
||||
" // @@protoc_insertion_point(field_add:$full_name$)\n"
|
||||
" return _add;\n"
|
||||
"}\n");
|
||||
|
||||
format(
|
||||
"inline const ::$proto_ns$::RepeatedPtrField< $type$ >&\n"
|
||||
"$classname$::$name$() const {\n"
|
||||
"$annotate_list$"
|
||||
" // @@protoc_insertion_point(field_list:$full_name$)\n"
|
||||
"$type_reference_function$"
|
||||
" return $field$$weak$;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::GenerateClearingCode(
|
||||
io::Printer* printer) const {
|
||||
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$.Clear();\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::GenerateMergingCode(
|
||||
io::Printer* printer) const {
|
||||
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
format("_this->$field$.MergeFrom(from.$field$);\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::GenerateSwappingCode(
|
||||
io::Printer* printer) const {
|
||||
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$.InternalSwap(&other->$field$);\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::GenerateConstructorCode(
|
||||
io::Printer* printer) const {
|
||||
// Not needed for repeated fields.
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::GenerateDestructorCode(
|
||||
io::Printer* printer) const {
|
||||
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
if (implicit_weak_field_) {
|
||||
format("$field$.~WeakRepeatedPtrField();\n");
|
||||
} else {
|
||||
format("$field$.~RepeatedPtrField();\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const {
|
||||
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
if (implicit_weak_field_) {
|
||||
format(
|
||||
"for (auto it = this->$field$.pointer_begin(),\n"
|
||||
" end = this->$field$.pointer_end(); it < end; ++it) {\n");
|
||||
if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
|
||||
format(
|
||||
" target = ::$proto_ns$::internal::WireFormatLite::\n"
|
||||
" InternalWrite$declared_type$($number$, "
|
||||
"**it, (**it).GetCachedSize(), target, stream);\n");
|
||||
} else {
|
||||
format(
|
||||
" target = stream->EnsureSpace(target);\n"
|
||||
" target = ::$proto_ns$::internal::WireFormatLite::\n"
|
||||
" InternalWrite$declared_type$($number$, **it, target, "
|
||||
"stream);\n");
|
||||
}
|
||||
format("}\n");
|
||||
} else {
|
||||
format(
|
||||
"for (unsigned i = 0,\n"
|
||||
" n = static_cast<unsigned>(this->_internal_$name$_size());"
|
||||
" i < n; i++) {\n");
|
||||
if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
|
||||
format(
|
||||
" const auto& repfield = this->_internal_$name$(i);\n"
|
||||
" target = ::$proto_ns$::internal::WireFormatLite::\n"
|
||||
" InternalWrite$declared_type$($number$, "
|
||||
"repfield, repfield.GetCachedSize(), target, stream);\n"
|
||||
"}\n");
|
||||
} else {
|
||||
format(
|
||||
" target = stream->EnsureSpace(target);\n"
|
||||
" target = ::$proto_ns$::internal::WireFormatLite::\n"
|
||||
" InternalWrite$declared_type$($number$, "
|
||||
"this->_internal_$name$(i), target, stream);\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::GenerateByteSize(
|
||||
io::Printer* printer) const {
|
||||
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"total_size += $tag_size$UL * this->_internal_$name$_size();\n"
|
||||
"for (const auto& msg : this->$field$) {\n"
|
||||
" total_size +=\n"
|
||||
" ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(msg);\n"
|
||||
"}\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($field$.weak))\n"
|
||||
" return false;\n");
|
||||
} else {
|
||||
format(
|
||||
"if (!::$proto_ns$::internal::AllAreInitialized($field$))\n"
|
||||
" return false;\n");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
148
libs/protobuf/src/google/protobuf/compiler/cpp/message_field.h
Normal file
148
libs/protobuf/src/google/protobuf/compiler/cpp/message_field.h
Normal file
@@ -0,0 +1,148 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "google/protobuf/compiler/cpp/field.h"
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
class MessageFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
MessageFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer);
|
||||
MessageFieldGenerator(const MessageFieldGenerator&) = delete;
|
||||
MessageFieldGenerator& operator=(const MessageFieldGenerator&) = delete;
|
||||
~MessageFieldGenerator() override;
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const override;
|
||||
void GenerateAccessorDeclarations(io::Printer* printer) const override;
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
|
||||
void GenerateNonInlineAccessorDefinitions(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateInternalAccessorDeclarations(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateInternalAccessorDefinitions(io::Printer* printer) const override;
|
||||
void GenerateClearingCode(io::Printer* printer) const override;
|
||||
void GenerateMessageClearingCode(io::Printer* printer) const override;
|
||||
void GenerateMergingCode(io::Printer* printer) const override;
|
||||
void GenerateSwappingCode(io::Printer* printer) const override;
|
||||
void GenerateDestructorCode(io::Printer* printer) const override;
|
||||
void GenerateConstructorCode(io::Printer* printer) const override {}
|
||||
void GenerateCopyConstructorCode(io::Printer* printer) const override;
|
||||
void GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateByteSize(io::Printer* printer) const override;
|
||||
void GenerateIsInitialized(io::Printer* printer) const override;
|
||||
void GenerateConstexprAggregateInitializer(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateAggregateInitializer(io::Printer* printer) const override;
|
||||
void GenerateCopyAggregateInitializer(io::Printer* printer) const override;
|
||||
|
||||
protected:
|
||||
const bool implicit_weak_field_;
|
||||
const bool has_required_fields_;
|
||||
};
|
||||
|
||||
class MessageOneofFieldGenerator : public MessageFieldGenerator {
|
||||
public:
|
||||
MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer);
|
||||
MessageOneofFieldGenerator(const MessageOneofFieldGenerator&) = delete;
|
||||
MessageOneofFieldGenerator& operator=(const MessageOneofFieldGenerator&) =
|
||||
delete;
|
||||
~MessageOneofFieldGenerator() override;
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
|
||||
void GenerateNonInlineAccessorDefinitions(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateClearingCode(io::Printer* printer) const override;
|
||||
|
||||
// MessageFieldGenerator, from which we inherit, overrides this so we need to
|
||||
// override it as well.
|
||||
void GenerateMessageClearingCode(io::Printer* printer) const override;
|
||||
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;
|
||||
};
|
||||
|
||||
class RepeatedMessageFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer);
|
||||
RepeatedMessageFieldGenerator(const RepeatedMessageFieldGenerator&) = delete;
|
||||
RepeatedMessageFieldGenerator& operator=(
|
||||
const RepeatedMessageFieldGenerator&) = delete;
|
||||
~RepeatedMessageFieldGenerator() override;
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const override;
|
||||
void GenerateAccessorDeclarations(io::Printer* printer) const override;
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
|
||||
void GenerateClearingCode(io::Printer* printer) const override;
|
||||
void GenerateMergingCode(io::Printer* printer) const override;
|
||||
void GenerateSwappingCode(io::Printer* printer) const override;
|
||||
void GenerateConstructorCode(io::Printer* printer) const override;
|
||||
void GenerateCopyConstructorCode(io::Printer* printer) const override {}
|
||||
void GenerateDestructorCode(io::Printer* printer) const override;
|
||||
void GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateByteSize(io::Printer* printer) const override;
|
||||
void GenerateIsInitialized(io::Printer* printer) const override;
|
||||
|
||||
private:
|
||||
const bool implicit_weak_field_;
|
||||
const bool has_required_fields_;
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__
|
||||
@@ -0,0 +1,64 @@
|
||||
// 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: seongkim@google.com (Seong Beom Kim)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__
|
||||
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/compiler/cpp/options.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
class MessageSCCAnalyzer;
|
||||
|
||||
// Provides an abstract interface to optimize message layout
|
||||
// by rearranging the fields of a message.
|
||||
class MessageLayoutHelper {
|
||||
public:
|
||||
virtual ~MessageLayoutHelper() {}
|
||||
|
||||
virtual void OptimizeLayout(std::vector<const FieldDescriptor*>* fields,
|
||||
const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer) = 0;
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__
|
||||
@@ -0,0 +1,272 @@
|
||||
// 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/unittest.pb.h"
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include "google/protobuf/descriptor.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
|
||||
namespace cpp_unittest {
|
||||
|
||||
|
||||
#if !defined(GOOGLE_CHECK_MESSAGE_SIZE)
|
||||
#define GOOGLE_CHECK_MESSAGE_SIZE(t, expected)
|
||||
#endif
|
||||
|
||||
// Mock structures to lock down the size of messages in a platform-independent
|
||||
// way. The commented sizes only apply when build with clang x86_64.
|
||||
struct MockMessageBase {
|
||||
virtual ~MockMessageBase() = default; // 8 bytes vtable
|
||||
void* internal_metadata; // 8 bytes
|
||||
};
|
||||
GOOGLE_CHECK_MESSAGE_SIZE(MockMessageBase, 16);
|
||||
|
||||
struct MockZeroFieldsBase : public MockMessageBase {
|
||||
int cached_size; // 4 bytes
|
||||
// + 4 bytes padding
|
||||
};
|
||||
GOOGLE_CHECK_MESSAGE_SIZE(MockZeroFieldsBase, 24);
|
||||
|
||||
struct MockExtensionSet {
|
||||
void* arena; // 8 bytes
|
||||
int16_t capacity; // 4 bytes
|
||||
int16_t size; // 4 bytes
|
||||
void* data; // 8 bytes
|
||||
};
|
||||
GOOGLE_CHECK_MESSAGE_SIZE(MockExtensionSet, 24);
|
||||
|
||||
struct MockRepeatedPtrField {
|
||||
void* arena; // 8 bytes
|
||||
int current_size; // 4 bytes
|
||||
int total_size; // 4 bytes
|
||||
void* data; // 8 bytes
|
||||
};
|
||||
GOOGLE_CHECK_MESSAGE_SIZE(MockRepeatedPtrField, 24);
|
||||
|
||||
struct MockRepeatedField {
|
||||
int current_size; // 4 bytes
|
||||
int total_size; // 4 bytes
|
||||
void* data; // 8 bytes
|
||||
};
|
||||
GOOGLE_CHECK_MESSAGE_SIZE(MockRepeatedField, 16);
|
||||
|
||||
TEST(GeneratedMessageTest, MockSizes) {
|
||||
// Consistency checks -- if these fail, the tests below will definitely fail.
|
||||
GOOGLE_CHECK_EQ(sizeof(MessageLite), sizeof(MockMessageBase));
|
||||
GOOGLE_CHECK_EQ(sizeof(Message), sizeof(MockMessageBase));
|
||||
GOOGLE_CHECK_EQ(sizeof(internal::ZeroFieldsBase), sizeof(MockZeroFieldsBase));
|
||||
GOOGLE_CHECK_EQ(sizeof(internal::ExtensionSet), sizeof(MockExtensionSet));
|
||||
GOOGLE_CHECK_EQ(sizeof(RepeatedPtrField<std::string>), sizeof(MockRepeatedPtrField));
|
||||
GOOGLE_CHECK_EQ(sizeof(RepeatedField<int>), sizeof(MockRepeatedField));
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, EmptyMessageSize) {
|
||||
EXPECT_EQ(sizeof(protobuf_unittest::TestEmptyMessage),
|
||||
sizeof(MockZeroFieldsBase));
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, ReservedSize) {
|
||||
EXPECT_EQ(sizeof(protobuf_unittest::TestReservedFields),
|
||||
sizeof(MockZeroFieldsBase));
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, EmptyMessageWithExtensionsSize) {
|
||||
struct MockGenerated : public MockMessageBase { // 16 bytes
|
||||
MockExtensionSet extensions; // 24 bytes
|
||||
int cached_size; // 4 bytes
|
||||
// + 4 bytes of padding
|
||||
};
|
||||
GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 48);
|
||||
EXPECT_EQ(sizeof(protobuf_unittest::TestEmptyMessageWithExtensions),
|
||||
sizeof(MockGenerated));
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, RecursiveMessageSize) {
|
||||
struct MockGenerated : public MockMessageBase { // 16 bytes
|
||||
int has_bits[1]; // 4 bytes
|
||||
int cached_size; // 4 bytes
|
||||
void* a; // 8 bytes
|
||||
int32_t i; // 4 bytes
|
||||
// + 4 bytes padding
|
||||
};
|
||||
GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 40);
|
||||
EXPECT_EQ(sizeof(protobuf_unittest::TestRecursiveMessage),
|
||||
sizeof(MockGenerated));
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, OneStringSize) {
|
||||
struct MockGenerated : public MockMessageBase { // 16 bytes
|
||||
int has_bits[1]; // 4 bytes
|
||||
int cached_size; // 4 bytes
|
||||
void* data; // 8 bytes
|
||||
};
|
||||
GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 32);
|
||||
EXPECT_EQ(sizeof(protobuf_unittest::OneString), sizeof(MockGenerated));
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, MoreStringSize) {
|
||||
struct MockGenerated : public MockMessageBase { // 16 bytes
|
||||
int cached_size; // 4 bytes
|
||||
MockRepeatedPtrField data; // 24 bytes
|
||||
// + 4 bytes padding
|
||||
};
|
||||
GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 48);
|
||||
EXPECT_EQ(sizeof(protobuf_unittest::MoreString), sizeof(MockGenerated));
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, Int32MessageSize) {
|
||||
struct MockGenerated : public MockMessageBase { // 16 bytes
|
||||
int has_bits[1]; // 4 bytes
|
||||
int cached_size; // 4 bytes
|
||||
int32_t data; // 4 bytes
|
||||
// + 4 bytes padding
|
||||
};
|
||||
GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 32);
|
||||
EXPECT_EQ(sizeof(protobuf_unittest::Int32Message), sizeof(MockGenerated));
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, Int64MessageSize) {
|
||||
struct MockGenerated : public MockMessageBase { // 16 bytes
|
||||
int has_bits[1]; // 4 bytes
|
||||
int cached_size; // 4 bytes
|
||||
int64_t data; // 8 bytes
|
||||
};
|
||||
GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 32);
|
||||
EXPECT_EQ(sizeof(protobuf_unittest::Int64Message), sizeof(MockGenerated));
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, BoolMessageSize) {
|
||||
struct MockGenerated : public MockMessageBase { // 16 bytes
|
||||
int has_bits[1]; // 4 bytes
|
||||
int cached_size; // 4 bytes
|
||||
bool data; // 1 byte
|
||||
// + 3 bytes padding
|
||||
};
|
||||
GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 32);
|
||||
EXPECT_EQ(sizeof(protobuf_unittest::BoolMessage), sizeof(MockGenerated));
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, OneofSize) {
|
||||
struct MockGenerated : public MockMessageBase { // 16 bytes
|
||||
void* foo; // 8 bytes
|
||||
int cached_size; // 4 bytes
|
||||
uint32_t oneof_case[1]; // 4 bytes
|
||||
};
|
||||
GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 32);
|
||||
EXPECT_EQ(sizeof(protobuf_unittest::TestOneof), sizeof(MockGenerated));
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, Oneof2Size) {
|
||||
struct MockGenerated : public MockMessageBase { // 16 bytes
|
||||
int has_bits[1]; // 4 bytes
|
||||
int cached_size; // 4 bytes
|
||||
void* baz_string; // 8 bytes
|
||||
int32_t baz_int; // 4 bytes
|
||||
// + 4 bytes padding
|
||||
void* foo; // 8 bytes
|
||||
void* bar; // 8 bytes
|
||||
uint32_t oneof_case[2]; // 8 bytes
|
||||
};
|
||||
GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 64);
|
||||
EXPECT_EQ(sizeof(protobuf_unittest::TestOneof2), sizeof(MockGenerated));
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, FieldOrderingsSize) {
|
||||
struct MockGenerated : public MockMessageBase { // 16 bytes
|
||||
int has_bits[1]; // 4 bytes
|
||||
int cached_size; // 4 bytes
|
||||
MockExtensionSet extensions; // 24 bytes
|
||||
void* my_string; // 8 bytes
|
||||
void* optional_nested_message; // 8 bytes
|
||||
int64_t my_int; // 8 bytes
|
||||
float my_float; // 4 bytes
|
||||
// + 4 bytes of padding
|
||||
};
|
||||
GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 80);
|
||||
EXPECT_EQ(sizeof(protobuf_unittest::TestFieldOrderings), sizeof(MockGenerated));
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, TestMessageSize) {
|
||||
// We expect the message to contain (not in this order):
|
||||
struct MockGenerated : public MockMessageBase { // 16 bytes
|
||||
int has_bits[1]; // 4 bytes
|
||||
int cached_size; // 4 bytes
|
||||
void* m4; // 8 bytes
|
||||
int64_t m2; // 8 bytes
|
||||
bool m1; // 1 bytes
|
||||
bool m3; // 1 bytes
|
||||
// + 2 bytes padding
|
||||
int m5; // 4 bytes
|
||||
int64_t m6; // 8 bytes
|
||||
};
|
||||
GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 56);
|
||||
EXPECT_EQ(sizeof(protobuf_unittest::TestMessageSize), sizeof(MockGenerated));
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageTest, PackedTypesSize) {
|
||||
struct MockGenerated : public MockMessageBase { // 16 bytes
|
||||
MockRepeatedField packed_int32; // 16 bytes
|
||||
int packed_int32_cached_byte_size; // 4 bytes + 4 bytes padding
|
||||
MockRepeatedField packed_int64; // 16 bytes
|
||||
int packed_int64_cached_byte_size; // 4 bytes + 4 bytes padding
|
||||
MockRepeatedField packed_uint32; // 16 bytes
|
||||
int packed_uint32_cached_byte_size; // 4 bytes + 4 bytes padding
|
||||
MockRepeatedField packed_uint64; // 16 bytes
|
||||
int packed_uint64_cached_byte_size; // 4 bytes + 4 bytes padding
|
||||
MockRepeatedField packed_sint32; // 16 bytes
|
||||
int packed_sint32_cached_byte_size; // 4 bytes + 4 bytes padding
|
||||
MockRepeatedField packed_sint64; // 16 bytes
|
||||
int packed_sint64_cached_byte_size; // 4 bytes + 4 bytes padding
|
||||
MockRepeatedField packed_fixed32; // 16 bytes
|
||||
MockRepeatedField packed_fixed64; // 16 bytes
|
||||
MockRepeatedField packed_sfixed32; // 16 bytes
|
||||
MockRepeatedField packed_sfixed64; // 16 bytes
|
||||
MockRepeatedField packed_float; // 16 bytes
|
||||
MockRepeatedField packed_double; // 16 bytes
|
||||
MockRepeatedField packed_bool; // 16 bytes
|
||||
MockRepeatedField packed_enum; // 16 bytes
|
||||
int packed_enum_cached_byte_size; // 4 bytes
|
||||
int cached_size; // 4 bytes
|
||||
};
|
||||
GOOGLE_CHECK_MESSAGE_SIZE(MockGenerated, 16 * 15 + 8 * 6 + 8);
|
||||
EXPECT_EQ(sizeof(protobuf_unittest::TestPackedTypes), sizeof(MockGenerated));
|
||||
}
|
||||
|
||||
} // namespace cpp_unittest
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
161
libs/protobuf/src/google/protobuf/compiler/cpp/metadata_test.cc
Normal file
161
libs/protobuf/src/google/protobuf/compiler/cpp/metadata_test.cc
Normal file
@@ -0,0 +1,161 @@
|
||||
// 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 <memory>
|
||||
|
||||
#include "google/protobuf/testing/file.h"
|
||||
#include "google/protobuf/testing/file.h"
|
||||
#include "google/protobuf/compiler/cpp/generator.h"
|
||||
#include "google/protobuf/compiler/command_line_interface.h"
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
#include "google/protobuf/testing/googletest.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include "google/protobuf/compiler/annotation_test_util.h"
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
namespace atu = annotation_test_util;
|
||||
|
||||
namespace {
|
||||
|
||||
class CppMetadataTest : public ::testing::Test {
|
||||
public:
|
||||
// Tries to capture a FileDescriptorProto, GeneratedCodeInfo, and output
|
||||
// code from the previously added file with name `filename`. Returns true on
|
||||
// success. If pb_h is non-null, expects a .pb.h and a .pb.h.meta (copied to
|
||||
// pb_h and pb_h_info respecfively); similarly for proto_h and proto_h_info.
|
||||
bool CaptureMetadata(const std::string& filename, FileDescriptorProto* file,
|
||||
std::string* pb_h, GeneratedCodeInfo* pb_h_info,
|
||||
std::string* proto_h, GeneratedCodeInfo* proto_h_info,
|
||||
std::string* pb_cc) {
|
||||
CommandLineInterface cli;
|
||||
CppGenerator cpp_generator;
|
||||
cli.RegisterGenerator("--cpp_out", &cpp_generator, "");
|
||||
std::string cpp_out =
|
||||
"--cpp_out=annotate_headers=true,"
|
||||
"annotation_pragma_name=pragma_name,"
|
||||
"annotation_guard_name=guard_name:" +
|
||||
TestTempDir();
|
||||
|
||||
const bool result = atu::RunProtoCompiler(filename, cpp_out, &cli, file);
|
||||
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string output_base = TestTempDir() + "/" + StripProto(filename);
|
||||
|
||||
if (pb_cc != nullptr) {
|
||||
GOOGLE_CHECK_OK(
|
||||
File::GetContents(output_base + ".pb.cc", pb_cc, true));
|
||||
}
|
||||
|
||||
if (pb_h != nullptr && pb_h_info != nullptr) {
|
||||
GOOGLE_CHECK_OK(
|
||||
File::GetContents(output_base + ".pb.h", pb_h, true));
|
||||
if (!atu::DecodeMetadata(output_base + ".pb.h.meta", pb_h_info)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (proto_h != nullptr && proto_h_info != nullptr) {
|
||||
GOOGLE_CHECK_OK(File::GetContents(output_base + ".proto.h", proto_h,
|
||||
true));
|
||||
if (!atu::DecodeMetadata(output_base + ".proto.h.meta", proto_h_info)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
const char kSmallTestFile[] =
|
||||
"syntax = \"proto2\";\n"
|
||||
"package foo;\n"
|
||||
"enum Enum { VALUE = 0; }\n"
|
||||
"message Message { }\n";
|
||||
|
||||
TEST_F(CppMetadataTest, CapturesEnumNames) {
|
||||
FileDescriptorProto file;
|
||||
GeneratedCodeInfo info;
|
||||
std::string pb_h;
|
||||
atu::AddFile("test.proto", kSmallTestFile);
|
||||
EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
|
||||
nullptr, nullptr));
|
||||
EXPECT_EQ("Enum", file.enum_type(0).name());
|
||||
std::vector<int> enum_path;
|
||||
enum_path.push_back(FileDescriptorProto::kEnumTypeFieldNumber);
|
||||
enum_path.push_back(0);
|
||||
const GeneratedCodeInfo::Annotation* enum_annotation =
|
||||
atu::FindAnnotationOnPath(info, "test.proto", enum_path);
|
||||
EXPECT_TRUE(nullptr != enum_annotation);
|
||||
EXPECT_TRUE(atu::AnnotationMatchesSubstring(pb_h, enum_annotation, "Enum"));
|
||||
}
|
||||
|
||||
TEST_F(CppMetadataTest, AddsPragma) {
|
||||
FileDescriptorProto file;
|
||||
GeneratedCodeInfo info;
|
||||
std::string pb_h;
|
||||
atu::AddFile("test.proto", kSmallTestFile);
|
||||
EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
|
||||
nullptr, nullptr));
|
||||
EXPECT_TRUE(pb_h.find("#ifdef guard_name") != std::string::npos);
|
||||
EXPECT_TRUE(pb_h.find("#pragma pragma_name \"test.pb.h.meta\"") !=
|
||||
std::string::npos);
|
||||
}
|
||||
|
||||
TEST_F(CppMetadataTest, CapturesMessageNames) {
|
||||
FileDescriptorProto file;
|
||||
GeneratedCodeInfo info;
|
||||
std::string pb_h;
|
||||
atu::AddFile("test.proto", kSmallTestFile);
|
||||
EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
|
||||
nullptr, nullptr));
|
||||
EXPECT_EQ("Message", file.message_type(0).name());
|
||||
std::vector<int> message_path;
|
||||
message_path.push_back(FileDescriptorProto::kMessageTypeFieldNumber);
|
||||
message_path.push_back(0);
|
||||
const GeneratedCodeInfo::Annotation* message_annotation =
|
||||
atu::FindAnnotationOnPath(info, "test.proto", message_path);
|
||||
EXPECT_TRUE(nullptr != message_annotation);
|
||||
EXPECT_TRUE(
|
||||
atu::AnnotationMatchesSubstring(pb_h, message_annotation, "Message"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
169
libs/protobuf/src/google/protobuf/compiler/cpp/move_unittest.cc
Normal file
169
libs/protobuf/src/google/protobuf/compiler/cpp/move_unittest.cc
Normal file
@@ -0,0 +1,169 @@
|
||||
// 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/stubs/common.h"
|
||||
#include "google/protobuf/test_util.h"
|
||||
#include "google/protobuf/unittest.pb.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#if LANG_CXX11
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
|
||||
namespace cpp_unittest {
|
||||
|
||||
// Moves are enabled only when compiling with a C++11 compiler or newer.
|
||||
#if LANG_CXX11
|
||||
|
||||
TEST(MovableMessageTest, MoveConstructor) {
|
||||
protobuf_unittest::TestAllTypes message1;
|
||||
TestUtil::SetAllFields(&message1);
|
||||
const auto* nested = &message1.optional_nested_message();
|
||||
|
||||
protobuf_unittest::TestAllTypes message2(std::move(message1));
|
||||
TestUtil::ExpectAllFieldsSet(message2);
|
||||
|
||||
// Check if the optional_nested_message was actually moved (and not just
|
||||
// copied).
|
||||
EXPECT_EQ(nested, &message2.optional_nested_message());
|
||||
EXPECT_NE(nested, &message1.optional_nested_message());
|
||||
}
|
||||
|
||||
TEST(MovableMessageTest, MoveAssignmentOperator) {
|
||||
protobuf_unittest::TestAllTypes message1;
|
||||
TestUtil::SetAllFields(&message1);
|
||||
const auto* nested = &message1.optional_nested_message();
|
||||
|
||||
protobuf_unittest::TestAllTypes message2;
|
||||
message2 = std::move(message1);
|
||||
TestUtil::ExpectAllFieldsSet(message2);
|
||||
|
||||
// Check if the optional_nested_message was actually moved (and not just
|
||||
// copied).
|
||||
EXPECT_EQ(nested, &message2.optional_nested_message());
|
||||
EXPECT_NE(nested, &message1.optional_nested_message());
|
||||
}
|
||||
|
||||
TEST(MovableMessageTest, SelfMoveAssignment) {
|
||||
// The `self` reference is necessary to defeat -Wself-move.
|
||||
protobuf_unittest::TestAllTypes message, &self = message;
|
||||
TestUtil::SetAllFields(&message);
|
||||
message = std::move(self);
|
||||
TestUtil::ExpectAllFieldsSet(message);
|
||||
}
|
||||
|
||||
TEST(MovableMessageTest, MoveSameArena) {
|
||||
Arena arena;
|
||||
|
||||
auto* message1_on_arena =
|
||||
Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
|
||||
TestUtil::SetAllFields(message1_on_arena);
|
||||
const auto* nested = &message1_on_arena->optional_nested_message();
|
||||
|
||||
auto* message2_on_arena =
|
||||
Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
|
||||
|
||||
// Moving messages on the same arena should lead to swapped pointers.
|
||||
*message2_on_arena = std::move(*message1_on_arena);
|
||||
EXPECT_EQ(nested, &message2_on_arena->optional_nested_message());
|
||||
}
|
||||
|
||||
TEST(MovableMessageTest, MoveDifferentArenas) {
|
||||
Arena arena1, arena2;
|
||||
|
||||
auto* message1_on_arena =
|
||||
Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena1);
|
||||
TestUtil::SetAllFields(message1_on_arena);
|
||||
const auto* nested = &message1_on_arena->optional_nested_message();
|
||||
|
||||
auto* message2_on_arena =
|
||||
Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena2);
|
||||
|
||||
// Moving messages on two different arenas should lead to a copy.
|
||||
*message2_on_arena = std::move(*message1_on_arena);
|
||||
EXPECT_NE(nested, &message2_on_arena->optional_nested_message());
|
||||
TestUtil::ExpectAllFieldsSet(*message1_on_arena);
|
||||
TestUtil::ExpectAllFieldsSet(*message2_on_arena);
|
||||
}
|
||||
|
||||
TEST(MovableMessageTest, MoveFromArena) {
|
||||
Arena arena;
|
||||
|
||||
auto* message1_on_arena =
|
||||
Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
|
||||
TestUtil::SetAllFields(message1_on_arena);
|
||||
const auto* nested = &message1_on_arena->optional_nested_message();
|
||||
|
||||
protobuf_unittest::TestAllTypes message2;
|
||||
|
||||
// Moving from a message on the arena should lead to a copy.
|
||||
message2 = std::move(*message1_on_arena);
|
||||
EXPECT_NE(nested, &message2.optional_nested_message());
|
||||
TestUtil::ExpectAllFieldsSet(*message1_on_arena);
|
||||
TestUtil::ExpectAllFieldsSet(message2);
|
||||
}
|
||||
|
||||
TEST(MovableMessageTest, MoveToArena) {
|
||||
Arena arena;
|
||||
|
||||
protobuf_unittest::TestAllTypes message1;
|
||||
TestUtil::SetAllFields(&message1);
|
||||
const auto* nested = &message1.optional_nested_message();
|
||||
|
||||
auto* message2_on_arena =
|
||||
Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena);
|
||||
|
||||
// Moving to a message on the arena should lead to a copy.
|
||||
*message2_on_arena = std::move(message1);
|
||||
EXPECT_NE(nested, &message2_on_arena->optional_nested_message());
|
||||
TestUtil::ExpectAllFieldsSet(message1);
|
||||
TestUtil::ExpectAllFieldsSet(*message2_on_arena);
|
||||
}
|
||||
|
||||
TEST(MovableMessageTest, Noexcept) {
|
||||
EXPECT_TRUE(
|
||||
std::is_nothrow_move_constructible<protobuf_unittest::TestAllTypes>());
|
||||
EXPECT_TRUE(std::is_nothrow_move_assignable<protobuf_unittest::TestAllTypes>());
|
||||
}
|
||||
|
||||
#endif // LANG_CXX11
|
||||
|
||||
} // namespace cpp_unittest
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
97
libs/protobuf/src/google/protobuf/compiler/cpp/names.h
Normal file
97
libs/protobuf/src/google/protobuf/compiler/cpp/names.h
Normal file
@@ -0,0 +1,97 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_NAMES_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_NAMES_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
class Descriptor;
|
||||
class EnumDescriptor;
|
||||
class EnumValueDescriptor;
|
||||
class FieldDescriptor;
|
||||
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
// Returns the unqualified C++ name.
|
||||
//
|
||||
// For example, if you had:
|
||||
// package foo.bar;
|
||||
// message Baz { message Moo {} }
|
||||
// Then the non-qualified version would be:
|
||||
// Baz_Moo
|
||||
std::string ClassName(const Descriptor* descriptor);
|
||||
std::string ClassName(const EnumDescriptor* enum_descriptor);
|
||||
|
||||
// Returns the fully qualified C++ name.
|
||||
//
|
||||
// For example, if you had:
|
||||
// package foo.bar;
|
||||
// message Baz { message Moo {} }
|
||||
// Then the qualified ClassName for Moo would be:
|
||||
// ::foo::bar::Baz_Moo
|
||||
std::string QualifiedClassName(const Descriptor* d);
|
||||
std::string QualifiedClassName(const EnumDescriptor* d);
|
||||
std::string QualifiedExtensionName(const FieldDescriptor* d);
|
||||
|
||||
// Get the (unqualified) name that should be used for this field in C++ code.
|
||||
// The name is coerced to lower-case to emulate proto1 behavior. People
|
||||
// should be using lowercase-with-underscores style for proto field names
|
||||
// anyway, so normally this just returns field->name().
|
||||
std::string FieldName(const FieldDescriptor* field);
|
||||
|
||||
// Requires that this field is in a oneof. Returns the (unqualified) case
|
||||
// constant for this field.
|
||||
std::string OneofCaseConstantName(const FieldDescriptor* field);
|
||||
// Returns the quafilied case constant for this field.
|
||||
std::string QualifiedOneofCaseConstantName(const FieldDescriptor* field);
|
||||
|
||||
// Get the (unqualified) name that should be used for this enum value in C++
|
||||
// code.
|
||||
std::string EnumValueName(const EnumValueDescriptor* enum_value);
|
||||
|
||||
// Strips ".proto" or ".protodevel" from the end of a filename.
|
||||
PROTOC_EXPORT std::string StripProto(const std::string& filename);
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_NAMES_H__
|
||||
103
libs/protobuf/src/google/protobuf/compiler/cpp/options.h
Normal file
103
libs/protobuf/src/google/protobuf/compiler/cpp/options.h
Normal file
@@ -0,0 +1,103 @@
|
||||
// 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: rennie@google.com (Jeffrey Rennie)
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
class AccessInfoMap;
|
||||
class SplitMap;
|
||||
|
||||
namespace cpp {
|
||||
|
||||
enum class EnforceOptimizeMode {
|
||||
kNoEnforcement, // Use the runtime specified by the file specific options.
|
||||
kSpeed, // Full runtime with a generated code implementation.
|
||||
kCodeSize, // Full runtime with a reflective implementation.
|
||||
kLiteRuntime,
|
||||
};
|
||||
|
||||
struct FieldListenerOptions {
|
||||
bool inject_field_listener_events = false;
|
||||
std::set<std::string> forbidden_field_listener_events;
|
||||
};
|
||||
|
||||
// Generator options (see generator.cc for a description of each):
|
||||
struct Options {
|
||||
const AccessInfoMap* access_info_map = nullptr;
|
||||
const SplitMap* split_map = nullptr;
|
||||
std::string dllexport_decl;
|
||||
std::string runtime_include_base;
|
||||
std::string annotation_pragma_name;
|
||||
std::string annotation_guard_name;
|
||||
FieldListenerOptions field_listener_options;
|
||||
EnforceOptimizeMode enforce_mode = EnforceOptimizeMode::kNoEnforcement;
|
||||
enum {
|
||||
kTCTableNever,
|
||||
kTCTableGuarded,
|
||||
kTCTableAlways
|
||||
} tctable_mode = kTCTableNever;
|
||||
int num_cc_files = 0;
|
||||
bool safe_boundary_check = false;
|
||||
bool proto_h = false;
|
||||
bool transitive_pb_h = true;
|
||||
bool annotate_headers = false;
|
||||
bool lite_implicit_weak_fields = false;
|
||||
bool bootstrap = false;
|
||||
bool opensource_runtime = false;
|
||||
bool annotate_accessor = false;
|
||||
bool unused_field_stripping = false;
|
||||
bool unverified_lazy_message_sets = false;
|
||||
bool profile_driven_inline_string = true;
|
||||
bool message_owned_arena_trial = false;
|
||||
bool force_split = false;
|
||||
bool profile_driven_split = true;
|
||||
#ifdef PROTOBUF_STABLE_EXPERIMENTS
|
||||
bool force_eagerly_verified_lazy = true;
|
||||
bool force_inline_string = true;
|
||||
#else // PROTOBUF_STABLE_EXPERIMENTS
|
||||
bool force_eagerly_verified_lazy = false;
|
||||
bool force_inline_string = false;
|
||||
#endif // !PROTOBUF_STABLE_EXPERIMENTS
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
|
||||
@@ -0,0 +1,253 @@
|
||||
// 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/compiler/cpp/padding_optimizer.h"
|
||||
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
namespace {
|
||||
|
||||
// FieldGroup is just a helper for PaddingOptimizer below. It holds a vector of
|
||||
// fields that are grouped together because they have compatible alignment, and
|
||||
// a preferred location in the final field ordering.
|
||||
class FieldGroup {
|
||||
public:
|
||||
FieldGroup() : preferred_location_(0) {}
|
||||
|
||||
// A group with a single field.
|
||||
FieldGroup(double preferred_location, const FieldDescriptor* field)
|
||||
: preferred_location_(preferred_location), fields_(1, field) {}
|
||||
|
||||
// Append the fields in 'other' to this group.
|
||||
void Append(const FieldGroup& other) {
|
||||
if (other.fields_.empty()) {
|
||||
return;
|
||||
}
|
||||
// Preferred location is the average among all the fields, so we weight by
|
||||
// the number of fields on each FieldGroup object.
|
||||
preferred_location_ = (preferred_location_ * fields_.size() +
|
||||
(other.preferred_location_ * other.fields_.size())) /
|
||||
(fields_.size() + other.fields_.size());
|
||||
fields_.insert(fields_.end(), other.fields_.begin(), other.fields_.end());
|
||||
}
|
||||
|
||||
void SetPreferredLocation(double location) { preferred_location_ = location; }
|
||||
const std::vector<const FieldDescriptor*>& fields() const { return fields_; }
|
||||
|
||||
// FieldGroup objects sort by their preferred location.
|
||||
bool operator<(const FieldGroup& other) const {
|
||||
return preferred_location_ < other.preferred_location_;
|
||||
}
|
||||
|
||||
private:
|
||||
// "preferred_location_" is an estimate of where this group should go in the
|
||||
// final list of fields. We compute this by taking the average index of each
|
||||
// field in this group in the original ordering of fields. This is very
|
||||
// approximate, but should put this group close to where its member fields
|
||||
// originally went.
|
||||
double preferred_location_;
|
||||
std::vector<const FieldDescriptor*> fields_;
|
||||
// We rely on the default copy constructor and operator= so this type can be
|
||||
// used in a vector.
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static void OptimizeLayoutHelper(std::vector<const FieldDescriptor*>* fields,
|
||||
const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer) {
|
||||
if (fields->empty()) return;
|
||||
|
||||
// The sorted numeric order of Family determines the declaration order in the
|
||||
// memory layout.
|
||||
enum Family {
|
||||
REPEATED = 0,
|
||||
STRING = 1,
|
||||
// Laying out LAZY_MESSAGE before MESSAGE allows a single memset to zero
|
||||
// MESSAGE and ZERO_INITIALIZABLE fields together.
|
||||
LAZY_MESSAGE = 2,
|
||||
MESSAGE = 3,
|
||||
ZERO_INITIALIZABLE = 4,
|
||||
OTHER = 5,
|
||||
kMaxFamily
|
||||
};
|
||||
|
||||
// First divide fields into those that align to 1 byte, 4 bytes or 8 bytes.
|
||||
std::vector<FieldGroup> aligned_to_1[kMaxFamily];
|
||||
std::vector<FieldGroup> aligned_to_4[kMaxFamily];
|
||||
std::vector<FieldGroup> aligned_to_8[kMaxFamily];
|
||||
for (int i = 0; i < fields->size(); ++i) {
|
||||
const FieldDescriptor* field = (*fields)[i];
|
||||
|
||||
Family f = OTHER;
|
||||
if (field->is_repeated()) {
|
||||
f = REPEATED;
|
||||
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
|
||||
f = STRING;
|
||||
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
f = MESSAGE;
|
||||
if (IsLazy(field, options, scc_analyzer)) {
|
||||
f = LAZY_MESSAGE;
|
||||
}
|
||||
} else if (CanInitializeByZeroing(field)) {
|
||||
f = ZERO_INITIALIZABLE;
|
||||
}
|
||||
|
||||
const int j = field->number();
|
||||
switch (EstimateAlignmentSize(field)) {
|
||||
case 1:
|
||||
aligned_to_1[f].push_back(FieldGroup(j, field));
|
||||
break;
|
||||
case 4:
|
||||
aligned_to_4[f].push_back(FieldGroup(j, field));
|
||||
break;
|
||||
case 8:
|
||||
aligned_to_8[f].push_back(FieldGroup(j, field));
|
||||
break;
|
||||
default:
|
||||
GOOGLE_LOG(FATAL) << "Unknown alignment size " << EstimateAlignmentSize(field)
|
||||
<< "for a field " << field->full_name() << ".";
|
||||
}
|
||||
}
|
||||
|
||||
// For each family, group fields to optimize padding.
|
||||
for (int f = 0; f < kMaxFamily; f++) {
|
||||
// Now group fields aligned to 1 byte into sets of 4, and treat those like a
|
||||
// single field aligned to 4 bytes.
|
||||
for (int i = 0; i < aligned_to_1[f].size(); i += 4) {
|
||||
FieldGroup field_group;
|
||||
for (int j = i; j < aligned_to_1[f].size() && j < i + 4; ++j) {
|
||||
field_group.Append(aligned_to_1[f][j]);
|
||||
}
|
||||
aligned_to_4[f].push_back(field_group);
|
||||
}
|
||||
// Sort by preferred location to keep fields as close to their field number
|
||||
// order as possible. Using stable_sort ensures that the output is
|
||||
// consistent across runs.
|
||||
std::stable_sort(aligned_to_4[f].begin(), aligned_to_4[f].end());
|
||||
|
||||
// Now group fields aligned to 4 bytes (or the 4-field groups created above)
|
||||
// into pairs, and treat those like a single field aligned to 8 bytes.
|
||||
for (int i = 0; i < aligned_to_4[f].size(); i += 2) {
|
||||
FieldGroup field_group;
|
||||
for (int j = i; j < aligned_to_4[f].size() && j < i + 2; ++j) {
|
||||
field_group.Append(aligned_to_4[f][j]);
|
||||
}
|
||||
if (i == aligned_to_4[f].size() - 1) {
|
||||
if (f == OTHER) {
|
||||
// Move incomplete 4-byte block to the beginning. This is done to
|
||||
// pair with the (possible) leftover blocks from the
|
||||
// ZERO_INITIALIZABLE family.
|
||||
field_group.SetPreferredLocation(-1);
|
||||
} else {
|
||||
// Move incomplete 4-byte block to the end.
|
||||
field_group.SetPreferredLocation(double{FieldDescriptor::kMaxNumber});
|
||||
}
|
||||
}
|
||||
aligned_to_8[f].push_back(field_group);
|
||||
}
|
||||
// Sort by preferred location.
|
||||
std::stable_sort(aligned_to_8[f].begin(), aligned_to_8[f].end());
|
||||
}
|
||||
|
||||
// Now pull out all the FieldDescriptors in order.
|
||||
fields->clear();
|
||||
for (int f = 0; f < kMaxFamily; ++f) {
|
||||
for (int i = 0; i < aligned_to_8[f].size(); ++i) {
|
||||
fields->insert(fields->end(), aligned_to_8[f][i].fields().begin(),
|
||||
aligned_to_8[f][i].fields().end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reorder 'fields' so that if the fields are output into a c++ class in the new
|
||||
// order, fields of similar family (see below) are together and within each
|
||||
// family, alignment padding is minimized.
|
||||
//
|
||||
// We try to do this while keeping each field as close as possible to its field
|
||||
// number order so that we don't reduce cache locality much for function that
|
||||
// access each field in order. Originally, OptimizePadding used declaration
|
||||
// order for its decisions, but generated code minus the serializer/parsers uses
|
||||
// the output of OptimizePadding as well (stored in
|
||||
// MessageGenerator::optimized_order_). Since the serializers use field number
|
||||
// order, we use that as a tie-breaker.
|
||||
//
|
||||
// We classify each field into a particular "family" of fields, that we perform
|
||||
// the same operation on in our generated functions.
|
||||
//
|
||||
// REPEATED is placed first, as the C++ compiler automatically initializes
|
||||
// these fields in layout order.
|
||||
//
|
||||
// STRING is grouped next, as our Clear/SharedCtor/SharedDtor walks it and
|
||||
// calls ArenaStringPtr::Destroy on each.
|
||||
//
|
||||
// LAZY_MESSAGE is grouped next, as it interferes with the ability to memset
|
||||
// non-repeated fields otherwise.
|
||||
//
|
||||
// MESSAGE is grouped next, as our Clear/SharedDtor code walks it and calls
|
||||
// delete on each. We initialize these fields with a NULL pointer (see
|
||||
// MessageFieldGenerator::GenerateConstructorCode), which allows them to be
|
||||
// memset.
|
||||
//
|
||||
// ZERO_INITIALIZABLE is memset in Clear/SharedCtor
|
||||
//
|
||||
// OTHER these fields are initialized one-by-one.
|
||||
//
|
||||
// If there are split fields in `fields`, they will be placed at the end. The
|
||||
// order within split fields follows the same rule, aka classify and order by
|
||||
// "family".
|
||||
void PaddingOptimizer::OptimizeLayout(
|
||||
std::vector<const FieldDescriptor*>* fields, const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer) {
|
||||
std::vector<const FieldDescriptor*> normal;
|
||||
std::vector<const FieldDescriptor*> split;
|
||||
for (const auto* field : *fields) {
|
||||
if (ShouldSplit(field, options)) {
|
||||
split.push_back(field);
|
||||
} else {
|
||||
normal.push_back(field);
|
||||
}
|
||||
}
|
||||
OptimizeLayoutHelper(&normal, options, scc_analyzer);
|
||||
OptimizeLayoutHelper(&split, options, scc_analyzer);
|
||||
fields->clear();
|
||||
fields->insert(fields->end(), normal.begin(), normal.end());
|
||||
fields->insert(fields->end(), split.begin(), split.end());
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
@@ -0,0 +1,65 @@
|
||||
// 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: seongkim@google.com (Seong Beom Kim)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__
|
||||
|
||||
#include "google/protobuf/compiler/cpp/message_layout_helper.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
// Rearranges the fields of a message to minimize padding.
|
||||
// Fields are grouped by the type and the size.
|
||||
// For example, grouping four boolean fields and one int32
|
||||
// field results in zero padding overhead. See OptimizeLayout's
|
||||
// comment for details.
|
||||
class PaddingOptimizer : public MessageLayoutHelper {
|
||||
public:
|
||||
PaddingOptimizer() {}
|
||||
~PaddingOptimizer() override {}
|
||||
|
||||
void OptimizeLayout(std::vector<const FieldDescriptor*>* fields,
|
||||
const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer) override;
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,141 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PARSE_FUNCTION_GENERATOR_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_PARSE_FUNCTION_GENERATOR_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/wire_format_lite.h"
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
#include "google/protobuf/compiler/cpp/options.h"
|
||||
#include "google/protobuf/generated_message_tctable_gen.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
// ParseFunctionGenerator generates the _InternalParse function for a message
|
||||
// (and any associated supporting members).
|
||||
class ParseFunctionGenerator {
|
||||
public:
|
||||
ParseFunctionGenerator(const Descriptor* descriptor, int max_has_bit_index,
|
||||
const std::vector<int>& has_bit_indices,
|
||||
const std::vector<int>& inlined_string_indices,
|
||||
const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer,
|
||||
const std::map<std::string, std::string>& vars);
|
||||
|
||||
// Emits class-level method declarations to `printer`:
|
||||
void GenerateMethodDecls(io::Printer* printer);
|
||||
|
||||
// Emits out-of-class method implementation definitions to `printer`:
|
||||
void GenerateMethodImpls(io::Printer* printer);
|
||||
|
||||
// Emits class-level data member declarations to `printer`:
|
||||
void GenerateDataDecls(io::Printer* printer);
|
||||
|
||||
// Emits out-of-class data member definitions to `printer`:
|
||||
void GenerateDataDefinitions(io::Printer* printer);
|
||||
|
||||
private:
|
||||
class GeneratedOptionProvider;
|
||||
|
||||
// Returns true if tailcall table code should be generated.
|
||||
bool should_generate_tctable() const;
|
||||
|
||||
// Returns true if tailcall table code should be generated, but inside an
|
||||
// #ifdef guard.
|
||||
bool should_generate_guarded_tctable() const {
|
||||
return should_generate_tctable() &&
|
||||
options_.tctable_mode == Options::kTCTableGuarded;
|
||||
}
|
||||
|
||||
// Generates a tail-calling `_InternalParse` function.
|
||||
void GenerateTailcallParseFunction(Formatter& format);
|
||||
|
||||
// Generates a fallback function for tailcall table-based parsing.
|
||||
void GenerateTailcallFallbackFunction(Formatter& format);
|
||||
|
||||
// Generates a looping `_InternalParse` function.
|
||||
void GenerateLoopingParseFunction(Formatter& format);
|
||||
|
||||
// Generates the tail-call table definition.
|
||||
void GenerateTailCallTable(Formatter& format);
|
||||
void GenerateFastFieldEntries(Formatter& format);
|
||||
void GenerateFieldEntries(Formatter& format);
|
||||
void GenerateFieldNames(Formatter& format);
|
||||
|
||||
// Generates parsing code for an `ArenaString` field.
|
||||
void GenerateArenaString(Formatter& format, const FieldDescriptor* field);
|
||||
|
||||
// Generates parsing code for a string-typed field.
|
||||
void GenerateStrings(Formatter& format, const FieldDescriptor* field,
|
||||
bool check_utf8);
|
||||
|
||||
// Generates parsing code for a length-delimited field (strings, messages,
|
||||
// etc.).
|
||||
void GenerateLengthDelim(Formatter& format, const FieldDescriptor* field);
|
||||
|
||||
// Generates the parsing code for a known field.
|
||||
void GenerateFieldBody(Formatter& format,
|
||||
google::protobuf::internal::WireFormatLite::WireType wiretype,
|
||||
const FieldDescriptor* field);
|
||||
|
||||
// Generates code to parse the next field from the input stream.
|
||||
void GenerateParseIterationBody(
|
||||
Formatter& format, const Descriptor* descriptor,
|
||||
const std::vector<const FieldDescriptor*>& fields);
|
||||
|
||||
// Generates a `switch` statement to parse each of `fields`.
|
||||
void GenerateFieldSwitch(Formatter& format,
|
||||
const std::vector<const FieldDescriptor*>& fields);
|
||||
|
||||
const Descriptor* descriptor_;
|
||||
MessageSCCAnalyzer* scc_analyzer_;
|
||||
const Options& options_;
|
||||
std::map<std::string, std::string> variables_;
|
||||
std::unique_ptr<internal::TailCallTableInfo> tc_table_info_;
|
||||
std::vector<int> inlined_string_indices_;
|
||||
const std::vector<const FieldDescriptor*> ordered_fields_;
|
||||
int num_hasbits_;
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_PARSE_FUNCTION_GENERATOR_H__
|
||||
@@ -0,0 +1,235 @@
|
||||
// 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)
|
||||
//
|
||||
// TODO(kenton): Share code with the versions of this test in other languages?
|
||||
// It seemed like parameterizing it would add more complexity than it is
|
||||
// worth.
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "google/protobuf/testing/file.h"
|
||||
#include "google/protobuf/testing/file.h"
|
||||
#include "google/protobuf/compiler/cpp/generator.h"
|
||||
#include "google/protobuf/compiler/command_line_interface.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "google/protobuf/io/zero_copy_stream.h"
|
||||
#include "google/protobuf/testing/googletest.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
namespace {
|
||||
|
||||
class TestGenerator : public CodeGenerator {
|
||||
public:
|
||||
TestGenerator() {}
|
||||
~TestGenerator() override {}
|
||||
|
||||
bool Generate(const FileDescriptor* file, const std::string& parameter,
|
||||
GeneratorContext* context, std::string* error) const override {
|
||||
TryInsert("test.pb.h", "includes", context);
|
||||
TryInsert("test.pb.h", "namespace_scope", context);
|
||||
TryInsert("test.pb.h", "global_scope", context);
|
||||
TryInsert("test.pb.h", "class_scope:foo.Bar", context);
|
||||
TryInsert("test.pb.h", "class_scope:foo.Bar.Baz", context);
|
||||
|
||||
TryInsert("test.pb.cc", "includes", context);
|
||||
TryInsert("test.pb.cc", "namespace_scope", context);
|
||||
TryInsert("test.pb.cc", "global_scope", context);
|
||||
|
||||
// Check field accessors for an optional int32:
|
||||
TryInsert("test.pb.h", "field_get:foo.Bar.optInt", context);
|
||||
TryInsert("test.pb.h", "field_set:foo.Bar.optInt", context);
|
||||
|
||||
// Check field accessors for a repeated int32:
|
||||
TryInsert("test.pb.h", "field_get:foo.Bar.repeatedInt", context);
|
||||
TryInsert("test.pb.h", "field_set:foo.Bar.repeatedInt", context);
|
||||
|
||||
// Check field accessors for a required string:
|
||||
TryInsert("test.pb.h", "field_get:foo.Bar.requiredString", context);
|
||||
TryInsert("test.pb.h", "field_set:foo.Bar.requiredString", context);
|
||||
TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredString", context);
|
||||
TryInsert("test.pb.h", "field_set_allocated:foo.Bar.requiredString",
|
||||
context);
|
||||
|
||||
// Check field accessors for a repeated string:
|
||||
TryInsert("test.pb.h", "field_get:foo.Bar.repeatedString", context);
|
||||
TryInsert("test.pb.h", "field_set:foo.Bar.repeatedString", context);
|
||||
TryInsert("test.pb.h", "field_set_char:foo.Bar.repeatedString", context);
|
||||
TryInsert("test.pb.h", "field_set_pointer:foo.Bar.repeatedString", context);
|
||||
TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedString", context);
|
||||
TryInsert("test.pb.h", "field_set_char:foo.Bar.repeatedString", context);
|
||||
TryInsert("test.pb.h", "field_set_pointer:foo.Bar.repeatedString", context);
|
||||
|
||||
// Check field accessors for an int inside oneof{}:
|
||||
TryInsert("test.pb.h", "field_get:foo.Bar.oneOfInt", context);
|
||||
TryInsert("test.pb.h", "field_set:foo.Bar.oneOfInt", context);
|
||||
|
||||
// Check field accessors for a string inside oneof{}:
|
||||
TryInsert("test.pb.h", "field_get:foo.Bar.oneOfString", context);
|
||||
TryInsert("test.pb.h", "field_set:foo.Bar.oneOfString", context);
|
||||
TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfString", context);
|
||||
TryInsert("test.pb.h", "field_set_allocated:foo.Bar.oneOfString", context);
|
||||
|
||||
// Check field accessors for an optional message:
|
||||
TryInsert("test.pb.h", "field_get:foo.Bar.optMessage", context);
|
||||
TryInsert("test.pb.h", "field_mutable:foo.Bar.optMessage", context);
|
||||
TryInsert("test.pb.h", "field_set_allocated:foo.Bar.optMessage", context);
|
||||
|
||||
// Check field accessors for a repeated message:
|
||||
TryInsert("test.pb.h", "field_add:foo.Bar.repeatedMessage", context);
|
||||
TryInsert("test.pb.h", "field_get:foo.Bar.repeatedMessage", context);
|
||||
TryInsert("test.pb.h", "field_list:foo.Bar.repeatedMessage", context);
|
||||
TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedMessage", context);
|
||||
TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedMessage",
|
||||
context);
|
||||
|
||||
// Check field accessors for a message inside oneof{}:
|
||||
TryInsert("test.pb.h", "field_get:foo.Bar.oneOfMessage", context);
|
||||
TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfMessage", context);
|
||||
TryInsert("test.pb.cc", "field_set_allocated:foo.Bar.oneOfMessage",
|
||||
context);
|
||||
|
||||
// Check field accessors for an optional enum:
|
||||
TryInsert("test.pb.h", "field_get:foo.Bar.optEnum", context);
|
||||
TryInsert("test.pb.h", "field_set:foo.Bar.optEnum", context);
|
||||
|
||||
// Check field accessors for a repeated enum:
|
||||
TryInsert("test.pb.h", "field_get:foo.Bar.repeatedEnum", context);
|
||||
TryInsert("test.pb.h", "field_set:foo.Bar.repeatedEnum", context);
|
||||
TryInsert("test.pb.h", "field_add:foo.Bar.repeatedEnum", context);
|
||||
TryInsert("test.pb.h", "field_list:foo.Bar.repeatedEnum", context);
|
||||
TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedEnum", context);
|
||||
|
||||
// Check field accessors for an enum inside oneof{}:
|
||||
TryInsert("test.pb.h", "field_get:foo.Bar.oneOfEnum", context);
|
||||
TryInsert("test.pb.h", "field_set:foo.Bar.oneOfEnum", context);
|
||||
|
||||
// Check field accessors for a required cord:
|
||||
TryInsert("test.pb.h", "field_get:foo.Bar.requiredCord", context);
|
||||
TryInsert("test.pb.h", "field_set:foo.Bar.requiredCord", context);
|
||||
TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredCord", context);
|
||||
|
||||
// Check field accessors for a repeated cord:
|
||||
TryInsert("test.pb.h", "field_get:foo.Bar.repeatedCord", context);
|
||||
TryInsert("test.pb.h", "field_set:foo.Bar.repeatedCord", context);
|
||||
TryInsert("test.pb.h", "field_add:foo.Bar.repeatedCord", context);
|
||||
TryInsert("test.pb.h", "field_list:foo.Bar.repeatedCord", context);
|
||||
TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedCord", context);
|
||||
TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedCord", context);
|
||||
|
||||
// Check field accessors for a cord inside oneof{}:
|
||||
TryInsert("test.pb.h", "field_get:foo.Bar.oneOfCord", context);
|
||||
TryInsert("test.pb.h", "field_set:foo.Bar.oneOfCord", context);
|
||||
TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfCord", context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TryInsert(const std::string& filename,
|
||||
const std::string& insertion_point,
|
||||
GeneratorContext* context) const {
|
||||
std::unique_ptr<io::ZeroCopyOutputStream> output(
|
||||
context->OpenForInsert(filename, insertion_point));
|
||||
io::Printer printer(output.get(), '$');
|
||||
printer.Print("// inserted $name$\n", "name", insertion_point);
|
||||
}
|
||||
};
|
||||
|
||||
// This test verifies that all the expected insertion points exist. It does
|
||||
// not verify that they are correctly-placed; that would require actually
|
||||
// compiling the output which is a bit more than I care to do for this test.
|
||||
TEST(CppPluginTest, PluginTest) {
|
||||
GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test.proto",
|
||||
"syntax = \"proto2\";\n"
|
||||
"package foo;\n"
|
||||
"\n"
|
||||
"enum Thud { VALUE = 0; }\n"
|
||||
"\n"
|
||||
"message Bar {\n"
|
||||
" message Baz {}\n"
|
||||
" optional int32 optInt = 1;\n"
|
||||
" repeated int32 repeatedInt = 2;\n"
|
||||
"\n"
|
||||
" required string requiredString = 3;\n"
|
||||
" repeated string repeatedString = 4;\n"
|
||||
"\n"
|
||||
" optional Baz optMessage = 6;\n"
|
||||
" repeated Baz repeatedMessage = 7;\n"
|
||||
"\n"
|
||||
" optional Thud optEnum = 8;\n"
|
||||
" repeated Thud repeatedEnum = 9;\n"
|
||||
"\n"
|
||||
" required string requiredCord = 10 [\n"
|
||||
" ctype = CORD\n"
|
||||
" ];\n"
|
||||
" repeated string repeatedCord = 11 [\n"
|
||||
" ctype = CORD\n"
|
||||
" ];\n"
|
||||
"\n"
|
||||
" oneof Moo {\n"
|
||||
" int64 oneOfInt = 20;\n"
|
||||
" string oneOfString = 21;\n"
|
||||
" Baz oneOfMessage = 22;\n"
|
||||
" Thud oneOfEnum = 23;"
|
||||
" string oneOfCord = 24 [\n"
|
||||
" ctype = CORD\n"
|
||||
" ];\n"
|
||||
" }\n"
|
||||
"}\n",
|
||||
true));
|
||||
|
||||
CommandLineInterface cli;
|
||||
cli.SetInputsAreProtoPathRelative(true);
|
||||
|
||||
CppGenerator cpp_generator;
|
||||
TestGenerator test_generator;
|
||||
cli.RegisterGenerator("--cpp_out", &cpp_generator, "");
|
||||
cli.RegisterGenerator("--test_out", &test_generator, "");
|
||||
|
||||
std::string proto_path = "-I" + TestTempDir();
|
||||
std::string cpp_out = "--cpp_out=" + TestTempDir();
|
||||
std::string test_out = "--test_out=" + TestTempDir();
|
||||
|
||||
const char* argv[] = {"protoc", proto_path.c_str(), cpp_out.c_str(),
|
||||
test_out.c_str(), "test.proto"};
|
||||
|
||||
EXPECT_EQ(0, cli.Run(5, argv));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
@@ -0,0 +1,540 @@
|
||||
// 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/compiler/cpp/primitive_field.h"
|
||||
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "google/protobuf/wire_format.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
using internal::WireFormatLite;
|
||||
|
||||
namespace {
|
||||
|
||||
// For encodings with fixed sizes, returns that size in bytes. Otherwise
|
||||
// returns -1.
|
||||
int FixedSize(FieldDescriptor::Type type) {
|
||||
switch (type) {
|
||||
case FieldDescriptor::TYPE_INT32:
|
||||
return -1;
|
||||
case FieldDescriptor::TYPE_INT64:
|
||||
return -1;
|
||||
case FieldDescriptor::TYPE_UINT32:
|
||||
return -1;
|
||||
case FieldDescriptor::TYPE_UINT64:
|
||||
return -1;
|
||||
case FieldDescriptor::TYPE_SINT32:
|
||||
return -1;
|
||||
case FieldDescriptor::TYPE_SINT64:
|
||||
return -1;
|
||||
case FieldDescriptor::TYPE_FIXED32:
|
||||
return WireFormatLite::kFixed32Size;
|
||||
case FieldDescriptor::TYPE_FIXED64:
|
||||
return WireFormatLite::kFixed64Size;
|
||||
case FieldDescriptor::TYPE_SFIXED32:
|
||||
return WireFormatLite::kSFixed32Size;
|
||||
case FieldDescriptor::TYPE_SFIXED64:
|
||||
return WireFormatLite::kSFixed64Size;
|
||||
case FieldDescriptor::TYPE_FLOAT:
|
||||
return WireFormatLite::kFloatSize;
|
||||
case FieldDescriptor::TYPE_DOUBLE:
|
||||
return WireFormatLite::kDoubleSize;
|
||||
|
||||
case FieldDescriptor::TYPE_BOOL:
|
||||
return WireFormatLite::kBoolSize;
|
||||
case FieldDescriptor::TYPE_ENUM:
|
||||
return -1;
|
||||
|
||||
case FieldDescriptor::TYPE_STRING:
|
||||
return -1;
|
||||
case FieldDescriptor::TYPE_BYTES:
|
||||
return -1;
|
||||
case FieldDescriptor::TYPE_GROUP:
|
||||
return -1;
|
||||
case FieldDescriptor::TYPE_MESSAGE:
|
||||
return -1;
|
||||
|
||||
// No default because we want the compiler to complain if any new
|
||||
// types are added.
|
||||
}
|
||||
GOOGLE_LOG(FATAL) << "Can't get here.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
void SetPrimitiveVariables(const FieldDescriptor* descriptor,
|
||||
std::map<std::string, std::string>* variables,
|
||||
const Options& options) {
|
||||
SetCommonFieldVariables(descriptor, variables, options);
|
||||
(*variables)["type"] = PrimitiveTypeName(options, descriptor->cpp_type());
|
||||
(*variables)["default"] = DefaultValue(options, descriptor);
|
||||
(*variables)["cached_byte_size_name"] = MakeVarintCachedSizeName(descriptor);
|
||||
bool cold = ShouldSplit(descriptor, options);
|
||||
(*variables)["cached_byte_size_field"] =
|
||||
MakeVarintCachedSizeFieldName(descriptor, cold);
|
||||
(*variables)["tag"] = absl::StrCat(internal::WireFormat::MakeTag(descriptor));
|
||||
int fixed_size = FixedSize(descriptor->type());
|
||||
if (fixed_size != -1) {
|
||||
(*variables)["fixed_size"] = absl::StrCat(fixed_size);
|
||||
}
|
||||
(*variables)["wire_format_field_type"] = FieldDescriptorProto_Type_Name(
|
||||
static_cast<FieldDescriptorProto_Type>(descriptor->type()));
|
||||
(*variables)["full_name"] = descriptor->full_name();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
PrimitiveFieldGenerator::PrimitiveFieldGenerator(
|
||||
const FieldDescriptor* descriptor, const Options& options)
|
||||
: FieldGenerator(descriptor, options) {
|
||||
SetPrimitiveVariables(descriptor, &variables_, options);
|
||||
}
|
||||
|
||||
PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
|
||||
|
||||
void PrimitiveFieldGenerator::GeneratePrivateMembers(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$type$ $name$_;\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::GenerateAccessorDeclarations(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"$deprecated_attr$$type$ ${1$$name$$}$() const;\n"
|
||||
"$deprecated_attr$void ${1$set_$name$$}$($type$ value);\n"
|
||||
"private:\n"
|
||||
"$type$ ${1$_internal_$name$$}$() const;\n"
|
||||
"void ${1$_internal_set_$name$$}$($type$ value);\n"
|
||||
"public:\n",
|
||||
descriptor_);
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"inline $type$ $classname$::_internal_$name$() const {\n"
|
||||
" return $field$;\n"
|
||||
"}\n"
|
||||
"inline $type$ $classname$::$name$() const {\n"
|
||||
"$annotate_get$"
|
||||
" // @@protoc_insertion_point(field_get:$full_name$)\n"
|
||||
" return _internal_$name$();\n"
|
||||
"}\n"
|
||||
"inline void $classname$::_internal_set_$name$($type$ value) {\n"
|
||||
" $set_hasbit$\n"
|
||||
" $field$ = value;\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$($type$ value) {\n"
|
||||
"$maybe_prepare_split_message$"
|
||||
" _internal_set_$name$(value);\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set:$full_name$)\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$ = $default$;\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("_this->_internal_set_$name$(from._internal_$name$());\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("swap($field$, other->$field$);\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::GenerateCopyConstructorCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("_this->$field$ = from.$field$;\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"target = stream->EnsureSpace(target);\n"
|
||||
"target = "
|
||||
"::_pbi::WireFormatLite::Write$declared_type$ToArray("
|
||||
"$number$, this->_internal_$name$(), target);\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::GenerateByteSize(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
int fixed_size = FixedSize(descriptor_->type());
|
||||
if (fixed_size == -1) {
|
||||
if (internal::WireFormat::TagSize(descriptor_->number(),
|
||||
descriptor_->type()) == 1) {
|
||||
// Adding one is very common and it turns out it can be done for
|
||||
// free inside of WireFormatLite, so we can save an instruction here.
|
||||
format(
|
||||
"total_size += ::_pbi::WireFormatLite::"
|
||||
"$declared_type$SizePlusOne(this->_internal_$name$());\n");
|
||||
} else {
|
||||
format(
|
||||
"total_size += $tag_size$ +\n"
|
||||
" ::_pbi::WireFormatLite::$declared_type$Size(\n"
|
||||
" this->_internal_$name$());\n");
|
||||
}
|
||||
} else {
|
||||
format("total_size += $tag_size$ + $fixed_size$;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::GenerateConstexprAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("/*decltype($field$)*/$default$");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::GenerateAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("decltype(Impl_::Split::$name$_){$default$}");
|
||||
return;
|
||||
}
|
||||
format("decltype($field$){$default$}");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::GenerateCopyAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("decltype($field$){}");
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator(
|
||||
const FieldDescriptor* descriptor, const Options& options)
|
||||
: PrimitiveFieldGenerator(descriptor, options) {
|
||||
SetCommonOneofFieldVariables(descriptor, &variables_);
|
||||
}
|
||||
|
||||
PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {}
|
||||
|
||||
void PrimitiveOneofFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"inline $type$ $classname$::_internal_$name$() const {\n"
|
||||
" if (_internal_has_$name$()) {\n"
|
||||
" return $field$;\n"
|
||||
" }\n"
|
||||
" return $default$;\n"
|
||||
"}\n"
|
||||
"inline void $classname$::_internal_set_$name$($type$ value) {\n"
|
||||
" if (!_internal_has_$name$()) {\n"
|
||||
" clear_$oneof_name$();\n"
|
||||
" set_has_$name$();\n"
|
||||
" }\n"
|
||||
" $field$ = value;\n"
|
||||
"}\n"
|
||||
"inline $type$ $classname$::$name$() const {\n"
|
||||
"$annotate_get$"
|
||||
" // @@protoc_insertion_point(field_get:$full_name$)\n"
|
||||
" return _internal_$name$();\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$($type$ value) {\n"
|
||||
" _internal_set_$name$(value);\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set:$full_name$)\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void PrimitiveOneofFieldGenerator::GenerateClearingCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$ = $default$;\n");
|
||||
}
|
||||
|
||||
void PrimitiveOneofFieldGenerator::GenerateSwappingCode(
|
||||
io::Printer* printer) const {
|
||||
// Don't print any swapping code. Swapping the union will swap this field.
|
||||
}
|
||||
|
||||
void PrimitiveOneofFieldGenerator::GenerateConstructorCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$ns$::_$classname$_default_instance_.$field$ = $default$;\n");
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator(
|
||||
const FieldDescriptor* descriptor, const Options& options)
|
||||
: FieldGenerator(descriptor, options) {
|
||||
SetPrimitiveVariables(descriptor, &variables_, options);
|
||||
|
||||
if (descriptor->is_packed()) {
|
||||
variables_["packed_reader"] = "ReadPackedPrimitive";
|
||||
variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline";
|
||||
} else {
|
||||
variables_["packed_reader"] = "ReadPackedPrimitiveNoInline";
|
||||
variables_["repeated_reader"] = "ReadRepeatedPrimitive";
|
||||
}
|
||||
}
|
||||
|
||||
RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::GeneratePrivateMembers(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("::$proto_ns$::RepeatedField< $type$ > $name$_;\n");
|
||||
if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 &&
|
||||
HasGeneratedMethods(descriptor_->file(), options_)) {
|
||||
format(
|
||||
"mutable ::$proto_ns$::internal::CachedSize "
|
||||
"$cached_byte_size_name$;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::GenerateAccessorDeclarations(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"private:\n"
|
||||
"$type$ ${1$_internal_$name$$}$(int index) const;\n"
|
||||
"const ::$proto_ns$::RepeatedField< $type$ >&\n"
|
||||
" ${1$_internal_$name$$}$() const;\n"
|
||||
"void ${1$_internal_add_$name$$}$($type$ value);\n"
|
||||
"::$proto_ns$::RepeatedField< $type$ >*\n"
|
||||
" ${1$_internal_mutable_$name$$}$();\n"
|
||||
"public:\n"
|
||||
"$deprecated_attr$$type$ ${1$$name$$}$(int index) const;\n"
|
||||
"$deprecated_attr$void ${1$set_$name$$}$(int index, $type$ value);\n"
|
||||
"$deprecated_attr$void ${1$add_$name$$}$($type$ value);\n"
|
||||
"$deprecated_attr$const ::$proto_ns$::RepeatedField< $type$ >&\n"
|
||||
" ${1$$name$$}$() const;\n"
|
||||
"$deprecated_attr$::$proto_ns$::RepeatedField< $type$ >*\n"
|
||||
" ${1$mutable_$name$$}$();\n",
|
||||
descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"inline $type$ $classname$::_internal_$name$(int index) const {\n"
|
||||
" return $field$.Get(index);\n"
|
||||
"}\n"
|
||||
"inline $type$ $classname$::$name$(int index) const {\n"
|
||||
"$annotate_get$"
|
||||
" // @@protoc_insertion_point(field_get:$full_name$)\n"
|
||||
" return _internal_$name$(index);\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$(int index, $type$ value) {\n"
|
||||
"$annotate_set$"
|
||||
" $field$.Set(index, value);\n"
|
||||
" // @@protoc_insertion_point(field_set:$full_name$)\n"
|
||||
"}\n"
|
||||
"inline void $classname$::_internal_add_$name$($type$ value) {\n"
|
||||
" $field$.Add(value);\n"
|
||||
"}\n"
|
||||
"inline void $classname$::add_$name$($type$ value) {\n"
|
||||
" _internal_add_$name$(value);\n"
|
||||
"$annotate_add$"
|
||||
" // @@protoc_insertion_point(field_add:$full_name$)\n"
|
||||
"}\n"
|
||||
"inline const ::$proto_ns$::RepeatedField< $type$ >&\n"
|
||||
"$classname$::_internal_$name$() const {\n"
|
||||
" return $field$;\n"
|
||||
"}\n"
|
||||
"inline const ::$proto_ns$::RepeatedField< $type$ >&\n"
|
||||
"$classname$::$name$() const {\n"
|
||||
"$annotate_list$"
|
||||
" // @@protoc_insertion_point(field_list:$full_name$)\n"
|
||||
" return _internal_$name$();\n"
|
||||
"}\n"
|
||||
"inline ::$proto_ns$::RepeatedField< $type$ >*\n"
|
||||
"$classname$::_internal_mutable_$name$() {\n"
|
||||
" return &$field$;\n"
|
||||
"}\n"
|
||||
"inline ::$proto_ns$::RepeatedField< $type$ >*\n"
|
||||
"$classname$::mutable_$name$() {\n"
|
||||
"$annotate_mutable_list$"
|
||||
" // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
|
||||
" return _internal_mutable_$name$();\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::GenerateClearingCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$.Clear();\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::GenerateMergingCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("_this->$field$.MergeFrom(from.$field$);\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::GenerateSwappingCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$.InternalSwap(&other->$field$);\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::GenerateDestructorCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$.~RepeatedField();\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (descriptor_->is_packed()) {
|
||||
if (FixedSize(descriptor_->type()) == -1) {
|
||||
format(
|
||||
"{\n"
|
||||
" int byte_size = "
|
||||
"$cached_byte_size_field$.Get();\n"
|
||||
" if (byte_size > 0) {\n"
|
||||
" target = stream->Write$declared_type$Packed(\n"
|
||||
" $number$, _internal_$name$(), byte_size, target);\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
} else {
|
||||
format(
|
||||
"if (this->_internal_$name$_size() > 0) {\n"
|
||||
" target = stream->WriteFixedPacked($number$, _internal_$name$(), "
|
||||
"target);\n"
|
||||
"}\n");
|
||||
}
|
||||
} else {
|
||||
format(
|
||||
"for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n"
|
||||
" target = stream->EnsureSpace(target);\n"
|
||||
" target = ::_pbi::WireFormatLite::"
|
||||
"Write$declared_type$ToArray($number$, this->_internal_$name$(i), "
|
||||
"target);\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::GenerateByteSize(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("{\n");
|
||||
format.Indent();
|
||||
int fixed_size = FixedSize(descriptor_->type());
|
||||
if (fixed_size == -1) {
|
||||
format(
|
||||
"size_t data_size = ::_pbi::WireFormatLite::\n"
|
||||
" $declared_type$Size(this->$field$);\n");
|
||||
} else {
|
||||
format(
|
||||
"unsigned int count = static_cast<unsigned "
|
||||
"int>(this->_internal_$name$_size());\n"
|
||||
"size_t data_size = $fixed_size$UL * count;\n");
|
||||
}
|
||||
|
||||
if (descriptor_->is_packed()) {
|
||||
format(
|
||||
"if (data_size > 0) {\n"
|
||||
" total_size += $tag_size$ +\n"
|
||||
" "
|
||||
"::_pbi::WireFormatLite::Int32Size(static_cast<$int32$>(data_size));\n"
|
||||
"}\n");
|
||||
if (FixedSize(descriptor_->type()) == -1) {
|
||||
format(
|
||||
"int cached_size = ::_pbi::ToCachedSize(data_size);\n"
|
||||
"$cached_byte_size_field$.Set(cached_size);\n");
|
||||
}
|
||||
format("total_size += data_size;\n");
|
||||
} else {
|
||||
format(
|
||||
"total_size += $tag_size$ *\n"
|
||||
" "
|
||||
"::_pbi::FromIntSize(this->_internal_$name$_size());\n"
|
||||
"total_size += data_size;\n");
|
||||
}
|
||||
format.Outdent();
|
||||
format("}\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::GenerateConstexprAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("/*decltype($field$)*/{}");
|
||||
if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 &&
|
||||
HasGeneratedMethods(descriptor_->file(), options_)) {
|
||||
format("\n, /*decltype($cached_byte_size_field$)*/{0}");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::GenerateAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("decltype($field$){arena}");
|
||||
if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 &&
|
||||
HasGeneratedMethods(descriptor_->file(), options_)) {
|
||||
// std::atomic has no move constructor, which prevents explicit aggregate
|
||||
// initialization pre-C++17.
|
||||
format("\n, /*decltype($cached_byte_size_field$)*/{0}");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::GenerateCopyAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
format("decltype($field$){from.$field$}");
|
||||
if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 &&
|
||||
HasGeneratedMethods(descriptor_->file(), options_)) {
|
||||
// std::atomic has no move constructor.
|
||||
format("\n, /*decltype($cached_byte_size_field$)*/{0}");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
126
libs/protobuf/src/google/protobuf/compiler/cpp/primitive_field.h
Normal file
126
libs/protobuf/src/google/protobuf/compiler/cpp/primitive_field.h
Normal file
@@ -0,0 +1,126 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "google/protobuf/compiler/cpp/field.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
class PrimitiveFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options);
|
||||
PrimitiveFieldGenerator(const PrimitiveFieldGenerator&) = delete;
|
||||
PrimitiveFieldGenerator& operator=(const PrimitiveFieldGenerator&) = delete;
|
||||
~PrimitiveFieldGenerator() override;
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const override;
|
||||
void GenerateAccessorDeclarations(io::Printer* printer) const override;
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
|
||||
void GenerateClearingCode(io::Printer* printer) const override;
|
||||
void GenerateMergingCode(io::Printer* printer) const override;
|
||||
void GenerateSwappingCode(io::Printer* printer) const override;
|
||||
void GenerateConstructorCode(io::Printer* printer) const override {}
|
||||
void GenerateCopyConstructorCode(io::Printer* printer) const override;
|
||||
void GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateByteSize(io::Printer* printer) const override;
|
||||
void GenerateConstexprAggregateInitializer(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateAggregateInitializer(io::Printer* printer) const override;
|
||||
void GenerateCopyAggregateInitializer(io::Printer* printer) const override;
|
||||
};
|
||||
|
||||
class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator {
|
||||
public:
|
||||
PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options);
|
||||
PrimitiveOneofFieldGenerator(const PrimitiveOneofFieldGenerator&) = delete;
|
||||
PrimitiveOneofFieldGenerator& operator=(const PrimitiveOneofFieldGenerator&) =
|
||||
delete;
|
||||
~PrimitiveOneofFieldGenerator() override;
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
|
||||
void GenerateClearingCode(io::Printer* printer) const override;
|
||||
void GenerateSwappingCode(io::Printer* printer) const override;
|
||||
void GenerateConstructorCode(io::Printer* printer) const override;
|
||||
};
|
||||
|
||||
class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options);
|
||||
RepeatedPrimitiveFieldGenerator(const RepeatedPrimitiveFieldGenerator&) =
|
||||
delete;
|
||||
RepeatedPrimitiveFieldGenerator& operator=(
|
||||
const RepeatedPrimitiveFieldGenerator&) = delete;
|
||||
~RepeatedPrimitiveFieldGenerator() override;
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const override;
|
||||
void GenerateAccessorDeclarations(io::Printer* printer) const override;
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
|
||||
void GenerateClearingCode(io::Printer* printer) const override;
|
||||
void GenerateMergingCode(io::Printer* printer) const override;
|
||||
void GenerateSwappingCode(io::Printer* printer) const override;
|
||||
void GenerateConstructorCode(io::Printer* printer) const override {}
|
||||
void GenerateCopyConstructorCode(io::Printer* /*printer*/) const override {
|
||||
GOOGLE_CHECK(!ShouldSplit(descriptor_, options_));
|
||||
}
|
||||
void GenerateDestructorCode(io::Printer* printer) const override;
|
||||
void GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateByteSize(io::Printer* printer) const override;
|
||||
void GenerateConstexprAggregateInitializer(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateAggregateInitializer(io::Printer* printer) const override;
|
||||
void GenerateCopyAggregateInitializer(io::Printer* printer) const override;
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__
|
||||
315
libs/protobuf/src/google/protobuf/compiler/cpp/service.cc
Normal file
315
libs/protobuf/src/google/protobuf/compiler/cpp/service.cc
Normal file
@@ -0,0 +1,315 @@
|
||||
// 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/compiler/cpp/service.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
void ServiceGenerator::GenerateDeclarations(io::Printer* printer) {
|
||||
auto vars = printer->WithVars(&vars_);
|
||||
printer->Emit(
|
||||
{
|
||||
{"virts", [&] { GenerateMethodSignatures(kVirtual, printer); }},
|
||||
{"impls", [&] { GenerateMethodSignatures(kNonVirtual, printer); }},
|
||||
},
|
||||
R"cc(
|
||||
class $classname$_Stub;
|
||||
class $dllexport_decl $$classname$ : public ::$proto_ns$::Service {
|
||||
protected:
|
||||
$classname$() = default;
|
||||
|
||||
public:
|
||||
using Stub = $classname$_Stub;
|
||||
|
||||
$classname$(const $classname$&) = delete;
|
||||
$classname$& operator=(const $classname$&) = delete;
|
||||
virtual ~$classname$() = default;
|
||||
|
||||
static const ::$proto_ns$::ServiceDescriptor* descriptor();
|
||||
|
||||
$virts$;
|
||||
|
||||
// implements Service ----------------------------------------------
|
||||
const ::$proto_ns$::ServiceDescriptor* GetDescriptor() override;
|
||||
|
||||
void CallMethod(const ::$proto_ns$::MethodDescriptor* method,
|
||||
::$proto_ns$::RpcController* controller,
|
||||
const ::$proto_ns$::Message* request,
|
||||
::$proto_ns$::Message* response,
|
||||
::google::protobuf::Closure* done) override;
|
||||
|
||||
const ::$proto_ns$::Message& GetRequestPrototype(
|
||||
const ::$proto_ns$::MethodDescriptor* method) const override;
|
||||
|
||||
const ::$proto_ns$::Message& GetResponsePrototype(
|
||||
const ::$proto_ns$::MethodDescriptor* method) const override;
|
||||
};
|
||||
|
||||
class $dllexport_decl $$classname$_Stub : public $classname$ {
|
||||
public:
|
||||
$classname$_Stub(::$proto_ns$::RpcChannel* channel);
|
||||
$classname$_Stub(::$proto_ns$::RpcChannel* channel,
|
||||
::$proto_ns$::Service::ChannelOwnership ownership);
|
||||
|
||||
$classname$_Stub(const $classname$_Stub&) = delete;
|
||||
$classname$_Stub& operator=(const $classname$_Stub&) = delete;
|
||||
|
||||
~$classname$_Stub() override;
|
||||
|
||||
inline ::$proto_ns$::RpcChannel* channel() { return channel_; }
|
||||
|
||||
// implements $classname$ ------------------------------------------
|
||||
$impls$;
|
||||
|
||||
private:
|
||||
::$proto_ns$::RpcChannel* channel_;
|
||||
bool owns_channel_;
|
||||
};
|
||||
)cc");
|
||||
}
|
||||
|
||||
void ServiceGenerator::GenerateMethodSignatures(VirtualOrNot virtual_or_not,
|
||||
io::Printer* printer) {
|
||||
for (int i = 0; i < descriptor_->method_count(); ++i) {
|
||||
const MethodDescriptor* method = descriptor_->method(i);
|
||||
|
||||
printer->Emit(
|
||||
{
|
||||
{"name", method->name()},
|
||||
{"input", QualifiedClassName(method->input_type(), *options_)},
|
||||
{"output", QualifiedClassName(method->output_type(), *options_)},
|
||||
{"virtual", virtual_or_not == kVirtual ? "virtual" : ""},
|
||||
{"override", virtual_or_not != kVirtual ? "override" : ""},
|
||||
},
|
||||
// No cc, clang-format does not format this string well due to the
|
||||
// $ override$ substitution.
|
||||
R"(
|
||||
$virtual $void $name$(::$proto_ns$::RpcController* controller,
|
||||
const $input$* request,
|
||||
$output$* response,
|
||||
::google::protobuf::Closure* done)$ override$;
|
||||
)");
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
void ServiceGenerator::GenerateImplementation(io::Printer* printer) {
|
||||
auto vars = printer->WithVars(&vars_);
|
||||
printer->Emit(
|
||||
{
|
||||
{"index", index_in_metadata_},
|
||||
{"no_impl_methods", [&] { GenerateNotImplementedMethods(printer); }},
|
||||
{"call_method", [&] { GenerateCallMethod(printer); }},
|
||||
{"get_request", [&] { GenerateGetPrototype(kRequest, printer); }},
|
||||
{"get_response", [&] { GenerateGetPrototype(kResponse, printer); }},
|
||||
{"stub_methods", [&] { GenerateStubMethods(printer); }},
|
||||
},
|
||||
R"cc(
|
||||
const ::$proto_ns$::ServiceDescriptor* $classname$::descriptor() {
|
||||
::$proto_ns$::internal::AssignDescriptors(&$desc_table$);
|
||||
return $file_level_service_descriptors$[$index$];
|
||||
}
|
||||
|
||||
const ::$proto_ns$::ServiceDescriptor* $classname$::GetDescriptor() {
|
||||
return descriptor();
|
||||
}
|
||||
|
||||
$no_impl_methods$;
|
||||
|
||||
$call_method$;
|
||||
|
||||
$get_request$;
|
||||
|
||||
$get_response$;
|
||||
|
||||
$classname$_Stub::$classname$_Stub(::$proto_ns$::RpcChannel* channel)
|
||||
: channel_(channel), owns_channel_(false) {}
|
||||
|
||||
$classname$_Stub::$classname$_Stub(
|
||||
::$proto_ns$::RpcChannel* channel,
|
||||
::$proto_ns$::Service::ChannelOwnership ownership)
|
||||
: channel_(channel),
|
||||
owns_channel_(ownership ==
|
||||
::$proto_ns$::Service::STUB_OWNS_CHANNEL) {}
|
||||
|
||||
$classname$_Stub::~$classname$_Stub() {
|
||||
if (owns_channel_) delete channel_;
|
||||
}
|
||||
|
||||
$stub_methods$;
|
||||
)cc");
|
||||
}
|
||||
|
||||
void ServiceGenerator::GenerateNotImplementedMethods(io::Printer* printer) {
|
||||
for (int i = 0; i < descriptor_->method_count(); ++i) {
|
||||
const MethodDescriptor* method = descriptor_->method(i);
|
||||
|
||||
printer->Emit(
|
||||
{
|
||||
{"name", method->name()},
|
||||
{"input", QualifiedClassName(method->input_type(), *options_)},
|
||||
{"output", QualifiedClassName(method->output_type(), *options_)},
|
||||
},
|
||||
R"cc(
|
||||
void $classname$::$name$(::$proto_ns$::RpcController* controller,
|
||||
const $input$*, $output$*, ::google::protobuf::Closure* done) {
|
||||
controller->SetFailed("Method $name$() not implemented.");
|
||||
done->Run();
|
||||
}
|
||||
)cc");
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceGenerator::GenerateCallMethod(io::Printer* printer) {
|
||||
printer->Emit(
|
||||
{
|
||||
{"index", absl::StrCat(index_in_metadata_)},
|
||||
{"cases", [&] { GenerateCallMethodCases(printer); }},
|
||||
},
|
||||
R"cc(
|
||||
void $classname$::CallMethod(
|
||||
const ::$proto_ns$::MethodDescriptor* method,
|
||||
::$proto_ns$::RpcController* controller,
|
||||
const ::$proto_ns$::Message* request,
|
||||
::$proto_ns$::Message* response, ::google::protobuf::Closure* done) {
|
||||
GOOGLE_DCHECK_EQ(method->service(), $file_level_service_descriptors$[$index$]);
|
||||
switch (method->index()) {
|
||||
$cases$;
|
||||
|
||||
default:
|
||||
GOOGLE_LOG(FATAL) << "Bad method index; this should never happen.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
)cc");
|
||||
}
|
||||
|
||||
void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
|
||||
io::Printer* printer) {
|
||||
printer->Emit(
|
||||
{
|
||||
{"which", which == kRequest ? "Request" : "Response"},
|
||||
{"which_type", which == kRequest ? "input" : "output"},
|
||||
{"cases",
|
||||
[&] {
|
||||
for (int i = 0; i < descriptor_->method_count(); ++i) {
|
||||
const MethodDescriptor* method = descriptor_->method(i);
|
||||
const Descriptor* type = which == kRequest
|
||||
? method->input_type()
|
||||
: method->output_type();
|
||||
|
||||
printer->Emit(
|
||||
{
|
||||
{"index", absl::StrCat(i)},
|
||||
{"type", QualifiedClassName(type, *options_)},
|
||||
},
|
||||
R"cc(
|
||||
case $index$:
|
||||
return $type$::default_instance();
|
||||
)cc");
|
||||
}
|
||||
}},
|
||||
},
|
||||
R"cc(
|
||||
const ::$proto_ns$::Message& $classname$::Get$which$Prototype(
|
||||
const ::$proto_ns$::MethodDescriptor* method) const {
|
||||
GOOGLE_DCHECK_EQ(method->service(), descriptor());
|
||||
switch (method->index()) {
|
||||
$cases$;
|
||||
|
||||
default:
|
||||
GOOGLE_LOG(FATAL) << "Bad method index; this should never happen.";
|
||||
return *::$proto_ns$::MessageFactory::generated_factory()
|
||||
->GetPrototype(method->$which_type$_type());
|
||||
}
|
||||
}
|
||||
)cc");
|
||||
}
|
||||
|
||||
void ServiceGenerator::GenerateCallMethodCases(io::Printer* printer) {
|
||||
for (int i = 0; i < descriptor_->method_count(); ++i) {
|
||||
const MethodDescriptor* method = descriptor_->method(i);
|
||||
printer->Emit(
|
||||
{
|
||||
{"name", method->name()},
|
||||
{"input", QualifiedClassName(method->input_type(), *options_)},
|
||||
{"output", QualifiedClassName(method->output_type(), *options_)},
|
||||
{"index", absl::StrCat(i)},
|
||||
},
|
||||
R"cc(
|
||||
case $index$:
|
||||
$name$(controller,
|
||||
::$proto_ns$::internal::DownCast<const $input$*>(request),
|
||||
::$proto_ns$::internal::DownCast<$output$*>(response), done);
|
||||
break;
|
||||
)cc");
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceGenerator::GenerateStubMethods(io::Printer* printer) {
|
||||
for (int i = 0; i < descriptor_->method_count(); ++i) {
|
||||
const MethodDescriptor* method = descriptor_->method(i);
|
||||
|
||||
printer->Emit(
|
||||
{
|
||||
{"name", method->name()},
|
||||
{"input", QualifiedClassName(method->input_type(), *options_)},
|
||||
{"output", QualifiedClassName(method->output_type(), *options_)},
|
||||
{"index", absl::StrCat(i)},
|
||||
},
|
||||
R"cc(
|
||||
void $classname$_Stub::$name$(::$proto_ns$::RpcController* controller,
|
||||
const $input$* request,
|
||||
$output$* response, ::google::protobuf::Closure* done) {
|
||||
channel_->CallMethod(descriptor()->method($index$), controller,
|
||||
request, response, done);
|
||||
}
|
||||
)cc");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
112
libs/protobuf/src/google/protobuf/compiler/cpp/service.h
Normal file
112
libs/protobuf/src/google/protobuf/compiler/cpp/service.h
Normal file
@@ -0,0 +1,112 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/compiler/cpp/options.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
class ServiceGenerator {
|
||||
public:
|
||||
// See generator.cc for the meaning of dllexport_decl.
|
||||
ServiceGenerator(const ServiceDescriptor* descriptor,
|
||||
const std::map<std::string, std::string>& vars,
|
||||
const Options& options)
|
||||
: descriptor_(descriptor), options_(&options), vars_(vars) {
|
||||
vars_["classname"] = descriptor_->name();
|
||||
vars_["full_name"] = descriptor_->full_name();
|
||||
}
|
||||
|
||||
ServiceGenerator(const ServiceGenerator&) = delete;
|
||||
ServiceGenerator& operator=(const ServiceGenerator&) = delete;
|
||||
ServiceGenerator(ServiceGenerator&&) = delete;
|
||||
ServiceGenerator& operator=(ServiceGenerator&&) = delete;
|
||||
|
||||
~ServiceGenerator() = default;
|
||||
|
||||
// Generate the class definitions for the service's interface and the
|
||||
// stub implementation.
|
||||
void GenerateDeclarations(io::Printer* printer);
|
||||
|
||||
// Generate implementations of everything declared by
|
||||
// GenerateDeclarations().
|
||||
void GenerateImplementation(io::Printer* printer);
|
||||
|
||||
private:
|
||||
enum RequestOrResponse { kRequest, kResponse };
|
||||
enum VirtualOrNot { kVirtual, kNonVirtual };
|
||||
|
||||
// Prints signatures for all methods in the
|
||||
void GenerateMethodSignatures(VirtualOrNot virtual_or_not,
|
||||
io::Printer* printer);
|
||||
|
||||
// Generate the default implementations of the service methods, which
|
||||
// produce a "not implemented" error.
|
||||
void GenerateNotImplementedMethods(io::Printer* printer);
|
||||
|
||||
// Generate the CallMethod() method of the service.
|
||||
void GenerateCallMethod(io::Printer* printer);
|
||||
|
||||
// Generate the Get{Request,Response}Prototype() methods.
|
||||
void GenerateGetPrototype(RequestOrResponse which, io::Printer* printer);
|
||||
|
||||
// Generate the cases in CallMethod().
|
||||
void GenerateCallMethodCases(io::Printer* printer);
|
||||
|
||||
// Generate the stub's implementations of the service methods.
|
||||
void GenerateStubMethods(io::Printer* printer);
|
||||
|
||||
const ServiceDescriptor* descriptor_;
|
||||
const Options* options_;
|
||||
std::map<std::string, std::string> vars_;
|
||||
|
||||
int index_in_metadata_;
|
||||
|
||||
friend class FileGenerator;
|
||||
};
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__
|
||||
944
libs/protobuf/src/google/protobuf/compiler/cpp/string_field.cc
Normal file
944
libs/protobuf/src/google/protobuf/compiler/cpp/string_field.cc
Normal file
@@ -0,0 +1,944 @@
|
||||
// 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/compiler/cpp/string_field.h"
|
||||
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "google/protobuf/compiler/cpp/helpers.h"
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
|
||||
#include "google/protobuf/stubs/strutil.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
namespace {
|
||||
|
||||
void SetStringVariables(const FieldDescriptor* descriptor,
|
||||
std::map<std::string, std::string>* variables,
|
||||
const Options& options) {
|
||||
SetCommonFieldVariables(descriptor, variables, options);
|
||||
|
||||
const std::string kNS = "::" + ProtobufNamespace(options) + "::internal::";
|
||||
const std::string kArenaStringPtr = kNS + "ArenaStringPtr";
|
||||
|
||||
(*variables)["default"] = DefaultValue(options, descriptor);
|
||||
(*variables)["default_length"] =
|
||||
absl::StrCat(descriptor->default_value_string().length());
|
||||
(*variables)["default_variable_name"] = MakeDefaultName(descriptor);
|
||||
(*variables)["default_variable_field"] = MakeDefaultFieldName(descriptor);
|
||||
|
||||
if (descriptor->default_value_string().empty()) {
|
||||
(*variables)["default_string"] = kNS + "GetEmptyStringAlreadyInited()";
|
||||
(*variables)["default_value"] = "&" + (*variables)["default_string"];
|
||||
(*variables)["lazy_variable_args"] = "";
|
||||
} else {
|
||||
(*variables)["lazy_variable"] =
|
||||
absl::StrCat(QualifiedClassName(descriptor->containing_type(), options),
|
||||
"::", MakeDefaultFieldName(descriptor));
|
||||
|
||||
(*variables)["default_string"] = (*variables)["lazy_variable"] + ".get()";
|
||||
(*variables)["default_value"] = "nullptr";
|
||||
(*variables)["lazy_variable_args"] = (*variables)["lazy_variable"] + ", ";
|
||||
}
|
||||
|
||||
(*variables)["pointer_type"] =
|
||||
descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
|
||||
(*variables)["setter"] =
|
||||
descriptor->type() == FieldDescriptor::TYPE_BYTES ? "SetBytes" : "Set";
|
||||
// NOTE: Escaped here to unblock proto1->proto2 migration.
|
||||
// TODO(liujisi): Extend this to apply for other conflicting methods.
|
||||
(*variables)["release_name"] =
|
||||
SafeFunctionName(descriptor->containing_type(), descriptor, "release_");
|
||||
(*variables)["full_name"] = descriptor->full_name();
|
||||
|
||||
if (options.opensource_runtime) {
|
||||
(*variables)["string_piece"] = "::std::string";
|
||||
} else {
|
||||
(*variables)["string_piece"] = "::absl::string_view";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options)
|
||||
: FieldGenerator(descriptor, options),
|
||||
inlined_(IsStringInlined(descriptor, options)) {
|
||||
SetStringVariables(descriptor, &variables_, options);
|
||||
}
|
||||
|
||||
StringFieldGenerator::~StringFieldGenerator() {}
|
||||
|
||||
void StringFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (!inlined_) {
|
||||
format("::$proto_ns$::internal::ArenaStringPtr $name$_;\n");
|
||||
} else {
|
||||
// Skips the automatic destruction; rather calls it explicitly if
|
||||
// allocating arena is null. This is required to support message-owned
|
||||
// arena (go/path-to-arenas) where a root proto is destroyed but
|
||||
// InlinedStringField may have arena-allocated memory.
|
||||
format("::$proto_ns$::internal::InlinedStringField $name$_;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateStaticMembers(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (!descriptor_->default_value_string().empty()) {
|
||||
format(
|
||||
"static const ::$proto_ns$::internal::LazyString"
|
||||
" $default_variable_name$;\n");
|
||||
}
|
||||
if (inlined_) {
|
||||
// `_init_inline_xxx` is used for initializing default instances.
|
||||
format("static std::true_type _init_inline_$name$_;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateAccessorDeclarations(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
// If we're using StringFieldGenerator for a field with a ctype, it's
|
||||
// because that ctype isn't actually implemented. In particular, this is
|
||||
// true of ctype=CORD and ctype=STRING_PIECE in the open source release.
|
||||
// We aren't releasing Cord because it has too many Google-specific
|
||||
// dependencies and we aren't releasing StringPiece because it's hardly
|
||||
// useful outside of Google and because it would get confusing to have
|
||||
// multiple instances of the StringPiece class in different libraries (PCRE
|
||||
// already includes it for their C++ bindings, which came from Google).
|
||||
//
|
||||
// In any case, we make all the accessors private while still actually
|
||||
// using a string to represent the field internally. This way, we can
|
||||
// guarantee that if we do ever implement the ctype, it won't break any
|
||||
// existing users who might be -- for whatever reason -- already using .proto
|
||||
// files that applied the ctype. The field can still be accessed via the
|
||||
// reflection interface since the reflection interface is independent of
|
||||
// the string's underlying representation.
|
||||
|
||||
bool unknown_ctype = descriptor_->options().ctype() !=
|
||||
EffectiveStringCType(descriptor_, options_);
|
||||
|
||||
if (unknown_ctype) {
|
||||
format.Outdent();
|
||||
format(
|
||||
" private:\n"
|
||||
" // Hidden due to unknown ctype option.\n");
|
||||
format.Indent();
|
||||
}
|
||||
|
||||
format(
|
||||
"$deprecated_attr$const std::string& ${1$$name$$}$() const;\n"
|
||||
"template <typename ArgT0 = const std::string&, typename... ArgT>\n"
|
||||
"$deprecated_attr$void ${1$set_$name$$}$(ArgT0&& arg0, ArgT... args);\n",
|
||||
descriptor_);
|
||||
format(
|
||||
"$deprecated_attr$std::string* ${1$mutable_$name$$}$();\n"
|
||||
"PROTOBUF_NODISCARD $deprecated_attr$std::string* "
|
||||
"${1$$release_name$$}$();\n"
|
||||
"$deprecated_attr$void ${1$set_allocated_$name$$}$(std::string* "
|
||||
"$name$);\n",
|
||||
descriptor_);
|
||||
format(
|
||||
"private:\n"
|
||||
"const std::string& _internal_$name$() const;\n"
|
||||
"inline PROTOBUF_ALWAYS_INLINE void "
|
||||
"_internal_set_$name$(const std::string& value);\n"
|
||||
"std::string* _internal_mutable_$name$();\n");
|
||||
if (inlined_) {
|
||||
format(
|
||||
"inline PROTOBUF_ALWAYS_INLINE bool _internal_$name$_donated() "
|
||||
"const;\n");
|
||||
}
|
||||
format("public:\n");
|
||||
|
||||
if (unknown_ctype) {
|
||||
format.Outdent();
|
||||
format(" public:\n");
|
||||
format.Indent();
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"inline const std::string& $classname$::$name$() const {\n"
|
||||
"$annotate_get$"
|
||||
" // @@protoc_insertion_point(field_get:$full_name$)\n");
|
||||
if (!descriptor_->default_value_string().empty()) {
|
||||
format(
|
||||
" if ($field$.IsDefault()) return "
|
||||
"$default_variable_field$.get();\n");
|
||||
}
|
||||
format(
|
||||
" return _internal_$name$();\n"
|
||||
"}\n");
|
||||
if (!inlined_) {
|
||||
format(
|
||||
"template <typename ArgT0, typename... ArgT>\n"
|
||||
"inline PROTOBUF_ALWAYS_INLINE\n"
|
||||
"void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n"
|
||||
"$maybe_prepare_split_message$"
|
||||
" $set_hasbit$\n"
|
||||
" $field$.$setter$(static_cast<ArgT0 &&>(arg0),"
|
||||
" args..., GetArenaForAllocation());\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set:$full_name$)\n"
|
||||
"}\n");
|
||||
} else {
|
||||
format(
|
||||
"template <typename ArgT0, typename... ArgT>\n"
|
||||
"inline PROTOBUF_ALWAYS_INLINE\n"
|
||||
"void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n"
|
||||
"$maybe_prepare_split_message$"
|
||||
" $set_hasbit$\n"
|
||||
" $field$.$setter$(static_cast<ArgT0 &&>(arg0),"
|
||||
" args..., GetArenaForAllocation(), _internal_$name$_donated(), "
|
||||
"&$donating_states_word$, $mask_for_undonate$, this);\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set:$full_name$)\n"
|
||||
"}\n"
|
||||
"inline bool $classname$::_internal_$name$_donated() const {\n"
|
||||
" bool value = $inlined_string_donated$\n"
|
||||
" return value;\n"
|
||||
"}\n");
|
||||
}
|
||||
format(
|
||||
"inline std::string* $classname$::mutable_$name$() {\n"
|
||||
"$maybe_prepare_split_message$"
|
||||
" std::string* _s = _internal_mutable_$name$();\n"
|
||||
"$annotate_mutable$"
|
||||
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
|
||||
" return _s;\n"
|
||||
"}\n"
|
||||
"inline const std::string& $classname$::_internal_$name$() const {\n"
|
||||
" return $field$.Get();\n"
|
||||
"}\n"
|
||||
"inline void $classname$::_internal_set_$name$(const std::string& "
|
||||
"value) {\n"
|
||||
" $set_hasbit$\n");
|
||||
if (!inlined_) {
|
||||
format(
|
||||
" $field$.Set(value, GetArenaForAllocation());\n"
|
||||
"}\n");
|
||||
} else {
|
||||
format(
|
||||
" $field$.Set(value, GetArenaForAllocation(),\n"
|
||||
" _internal_$name$_donated(), &$donating_states_word$, "
|
||||
"$mask_for_undonate$, this);\n"
|
||||
"}\n");
|
||||
}
|
||||
format(
|
||||
"inline std::string* $classname$::_internal_mutable_$name$() {\n"
|
||||
" $set_hasbit$\n");
|
||||
if (!inlined_) {
|
||||
format(
|
||||
" return $field$.Mutable($lazy_variable_args$"
|
||||
"GetArenaForAllocation());\n"
|
||||
"}\n");
|
||||
} else {
|
||||
format(
|
||||
" return $field$.Mutable($lazy_variable_args$"
|
||||
"GetArenaForAllocation(), _internal_$name$_donated(), "
|
||||
"&$donating_states_word$, $mask_for_undonate$, this);\n"
|
||||
"}\n");
|
||||
}
|
||||
format(
|
||||
"inline std::string* $classname$::$release_name$() {\n"
|
||||
"$annotate_release$"
|
||||
"$maybe_prepare_split_message$"
|
||||
" // @@protoc_insertion_point(field_release:$full_name$)\n");
|
||||
|
||||
if (internal::cpp::HasHasbit(descriptor_)) {
|
||||
format(
|
||||
" if (!_internal_has_$name$()) {\n"
|
||||
" return nullptr;\n"
|
||||
" }\n"
|
||||
" $clear_hasbit$\n");
|
||||
if (!inlined_) {
|
||||
format(" auto* p = $field$.Release();\n");
|
||||
if (descriptor_->default_value_string().empty()) {
|
||||
format(
|
||||
"#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"
|
||||
" $field$.Set(\"\", GetArenaForAllocation());\n"
|
||||
"#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n");
|
||||
}
|
||||
format(" return p;\n");
|
||||
} else {
|
||||
format(
|
||||
" return $field$.Release(GetArenaForAllocation(), "
|
||||
"_internal_$name$_donated());\n");
|
||||
}
|
||||
} else {
|
||||
format(" return $field$.Release();\n");
|
||||
}
|
||||
|
||||
format(
|
||||
"}\n"
|
||||
"inline void $classname$::set_allocated_$name$(std::string* $name$) {\n"
|
||||
"$maybe_prepare_split_message$");
|
||||
|
||||
auto nonempty = [this](const char* fn) {
|
||||
auto var_it = variables_.find(fn);
|
||||
return var_it != variables_.end() && !var_it->second.empty();
|
||||
};
|
||||
if (nonempty("set_hasbit") || nonempty("clear_hasbit")) {
|
||||
format(
|
||||
" if ($name$ != nullptr) {\n"
|
||||
" $set_hasbit$\n"
|
||||
" } else {\n"
|
||||
" $clear_hasbit$\n"
|
||||
" }\n");
|
||||
}
|
||||
if (!inlined_) {
|
||||
format(" $field$.SetAllocated($name$, GetArenaForAllocation());\n");
|
||||
if (descriptor_->default_value_string().empty()) {
|
||||
format(
|
||||
"#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"
|
||||
" if ($field$.IsDefault()) {\n"
|
||||
" $field$.Set(\"\", GetArenaForAllocation());\n"
|
||||
" }\n"
|
||||
"#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n");
|
||||
}
|
||||
} else {
|
||||
// Currently, string fields with default value can't be inlined.
|
||||
format(
|
||||
" $field$.SetAllocated(nullptr, $name$, GetArenaForAllocation(), "
|
||||
"_internal_$name$_donated(), &$donating_states_word$, "
|
||||
"$mask_for_undonate$, this);\n");
|
||||
}
|
||||
format(
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateNonInlineAccessorDefinitions(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (!descriptor_->default_value_string().empty()) {
|
||||
format(
|
||||
"const ::$proto_ns$::internal::LazyString "
|
||||
"$classname$::$default_variable_field$"
|
||||
"{{{$default$, $default_length$}}, {nullptr}};\n");
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (descriptor_->default_value_string().empty()) {
|
||||
format("$field$.ClearToEmpty();\n");
|
||||
} else {
|
||||
GOOGLE_DCHECK(!inlined_);
|
||||
format(
|
||||
"$field$.ClearToDefault($lazy_variable$, GetArenaForAllocation());\n");
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateMessageClearingCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
// Two-dimension specialization here: supporting arenas, field presence, or
|
||||
// not, and default value is the empty string or not. Complexity here ensures
|
||||
// the minimal number of branches / amount of extraneous code at runtime
|
||||
// (given that the below methods are inlined one-liners)!
|
||||
|
||||
// If we have a hasbit, then the Clear() method of the protocol buffer
|
||||
// will have checked that this field is set. If so, we can avoid redundant
|
||||
// checks against the default variable.
|
||||
const bool must_be_present = internal::cpp::HasHasbit(descriptor_);
|
||||
|
||||
if (inlined_ && must_be_present) {
|
||||
// Calling mutable_$name$() gives us a string reference and sets the has bit
|
||||
// for $name$ (in proto2). We may get here when the string field is inlined
|
||||
// but the string's contents have not been changed by the user, so we cannot
|
||||
// make an assertion about the contents of the string and could never make
|
||||
// an assertion about the string instance.
|
||||
//
|
||||
// For non-inlined strings, we distinguish from non-default by comparing
|
||||
// instances, rather than contents.
|
||||
format("$DCHK$(!$field$.IsDefault());\n");
|
||||
}
|
||||
|
||||
if (descriptor_->default_value_string().empty()) {
|
||||
if (must_be_present) {
|
||||
format("$field$.ClearNonDefaultToEmpty();\n");
|
||||
} else {
|
||||
format("$field$.ClearToEmpty();\n");
|
||||
}
|
||||
} else {
|
||||
// Clear to a non-empty default is more involved, as we try to use the
|
||||
// Arena if one is present and may need to reallocate the string.
|
||||
format(
|
||||
"$field$.ClearToDefault($lazy_variable$, GetArenaForAllocation());\n ");
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
// TODO(gpike): improve this
|
||||
format("_this->_internal_set_$name$(from._internal_$name$());\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (!inlined_) {
|
||||
format(
|
||||
"::$proto_ns$::internal::ArenaStringPtr::InternalSwap(\n"
|
||||
" &$field$, lhs_arena,\n"
|
||||
" &other->$field$, rhs_arena\n"
|
||||
");\n");
|
||||
} else {
|
||||
format(
|
||||
"::$proto_ns$::internal::InlinedStringField::InternalSwap(\n"
|
||||
" &$field$, lhs_arena, "
|
||||
"($inlined_string_donated_array$[0] & 0x1u) == 0, this,\n"
|
||||
" &other->$field$, rhs_arena, "
|
||||
"(other->$inlined_string_donated_array$[0] & 0x1u) == 0, other);\n");
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateConstructorCode(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (inlined_ && descriptor_->default_value_string().empty()) {
|
||||
return;
|
||||
}
|
||||
GOOGLE_DCHECK(!inlined_);
|
||||
format("$field$.InitDefault();\n");
|
||||
if (IsString(descriptor_, options_) &&
|
||||
descriptor_->default_value_string().empty()) {
|
||||
format(
|
||||
"#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"
|
||||
" $field$.Set(\"\", GetArenaForAllocation());\n"
|
||||
"#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n");
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateCopyConstructorCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
GenerateConstructorCode(printer);
|
||||
if (inlined_) {
|
||||
format("new (&_this->$field$) ::_pbi::InlinedStringField();\n");
|
||||
}
|
||||
|
||||
if (internal::cpp::HasHasbit(descriptor_)) {
|
||||
format("if (from._internal_has_$name$()) {\n");
|
||||
} else {
|
||||
format("if (!from._internal_$name$().empty()) {\n");
|
||||
}
|
||||
|
||||
format.Indent();
|
||||
|
||||
if (!inlined_) {
|
||||
format(
|
||||
"_this->$field$.Set(from._internal_$name$(), \n"
|
||||
" _this->GetArenaForAllocation());\n");
|
||||
} else {
|
||||
format(
|
||||
"_this->$field$.Set(from._internal_$name$(),\n"
|
||||
" _this->GetArenaForAllocation(), _this->_internal_$name$_donated(), "
|
||||
"&_this->$donating_states_word$, $mask_for_undonate$, _this);\n");
|
||||
}
|
||||
|
||||
format.Outdent();
|
||||
format("}\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (!inlined_) {
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("$cached_split_ptr$->$name$_.Destroy();\n");
|
||||
return;
|
||||
}
|
||||
format("$field$.Destroy();\n");
|
||||
return;
|
||||
}
|
||||
// Explicitly calls ~InlinedStringField as its automatic call is disabled.
|
||||
// Destructor has been implicitly skipped as a union, and even the
|
||||
// message-owned arena is enabled, arena could still be missing for
|
||||
// Arena::CreateMessage(nullptr).
|
||||
GOOGLE_DCHECK(!ShouldSplit(descriptor_, options_));
|
||||
format("$field$.~InlinedStringField();\n");
|
||||
}
|
||||
|
||||
ArenaDtorNeeds StringFieldGenerator::NeedsArenaDestructor() const {
|
||||
return inlined_ ? ArenaDtorNeeds::kOnDemand : ArenaDtorNeeds::kNone;
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateArenaDestructorCode(
|
||||
io::Printer* printer) const {
|
||||
if (!inlined_) return;
|
||||
Formatter format(printer, variables_);
|
||||
// _this is the object being destructed (we are inside a static method here).
|
||||
format(
|
||||
"if (!_this->_internal_$name$_donated()) {\n"
|
||||
" _this->$field$.~InlinedStringField();\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
|
||||
GenerateUtf8CheckCodeForString(
|
||||
descriptor_, options_, false,
|
||||
"this->_internal_$name$().data(), "
|
||||
"static_cast<int>(this->_internal_$name$().length()),\n",
|
||||
format);
|
||||
}
|
||||
format(
|
||||
"target = stream->Write$declared_type$MaybeAliased(\n"
|
||||
" $number$, this->_internal_$name$(), target);\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateByteSize(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"total_size += $tag_size$ +\n"
|
||||
" ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n"
|
||||
" this->_internal_$name$());\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateConstexprAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (inlined_) {
|
||||
format("/*decltype($field$)*/{nullptr, false}");
|
||||
return;
|
||||
}
|
||||
format(
|
||||
"/*decltype($field$)*/{&::_pbi::fixed_address_empty_string, "
|
||||
"::_pbi::ConstantInitialized{}}");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
GOOGLE_CHECK(!inlined_);
|
||||
format("decltype(Impl_::Split::$name$_){}");
|
||||
return;
|
||||
}
|
||||
if (!inlined_) {
|
||||
format("decltype($field$){}");
|
||||
} else {
|
||||
format("decltype($field$)(arena)");
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateCopyAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("decltype($field$){}");
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
StringOneofFieldGenerator::StringOneofFieldGenerator(
|
||||
const FieldDescriptor* descriptor, const Options& options)
|
||||
: StringFieldGenerator(descriptor, options) {
|
||||
SetCommonOneofFieldVariables(descriptor, &variables_);
|
||||
variables_["field_name"] = UnderscoresToCamelCase(descriptor->name(), true);
|
||||
variables_["oneof_index"] =
|
||||
absl::StrCat(descriptor->containing_oneof()->index());
|
||||
}
|
||||
|
||||
StringOneofFieldGenerator::~StringOneofFieldGenerator() {}
|
||||
|
||||
void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"inline const std::string& $classname$::$name$() const {\n"
|
||||
"$annotate_get$"
|
||||
" // @@protoc_insertion_point(field_get:$full_name$)\n"
|
||||
" return _internal_$name$();\n"
|
||||
"}\n"
|
||||
"template <typename ArgT0, typename... ArgT>\n"
|
||||
"inline void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n"
|
||||
" if (!_internal_has_$name$()) {\n"
|
||||
" clear_$oneof_name$();\n"
|
||||
" set_has_$name$();\n"
|
||||
" $field$.InitDefault();\n"
|
||||
" }\n"
|
||||
" $field$.$setter$("
|
||||
" static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set:$full_name$)\n"
|
||||
"}\n"
|
||||
"inline std::string* $classname$::mutable_$name$() {\n"
|
||||
" std::string* _s = _internal_mutable_$name$();\n"
|
||||
"$annotate_mutable$"
|
||||
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
|
||||
" return _s;\n"
|
||||
"}\n"
|
||||
"inline const std::string& $classname$::_internal_$name$() const {\n"
|
||||
" if (_internal_has_$name$()) {\n"
|
||||
" return $field$.Get();\n"
|
||||
" }\n"
|
||||
" return $default_string$;\n"
|
||||
"}\n"
|
||||
"inline void $classname$::_internal_set_$name$(const std::string& "
|
||||
"value) {\n"
|
||||
" if (!_internal_has_$name$()) {\n"
|
||||
" clear_$oneof_name$();\n"
|
||||
" set_has_$name$();\n"
|
||||
" $field$.InitDefault();\n"
|
||||
" }\n"
|
||||
" $field$.Set(value, GetArenaForAllocation());\n"
|
||||
"}\n");
|
||||
format(
|
||||
"inline std::string* $classname$::_internal_mutable_$name$() {\n"
|
||||
" if (!_internal_has_$name$()) {\n"
|
||||
" clear_$oneof_name$();\n"
|
||||
" set_has_$name$();\n"
|
||||
" $field$.InitDefault();\n"
|
||||
" }\n"
|
||||
" return $field$.Mutable($lazy_variable_args$"
|
||||
" GetArenaForAllocation());\n"
|
||||
"}\n"
|
||||
"inline std::string* $classname$::$release_name$() {\n"
|
||||
"$annotate_release$"
|
||||
" // @@protoc_insertion_point(field_release:$full_name$)\n"
|
||||
" if (_internal_has_$name$()) {\n"
|
||||
" clear_has_$oneof_name$();\n"
|
||||
" return $field$.Release();\n"
|
||||
" } else {\n"
|
||||
" return nullptr;\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_allocated_$name$(std::string* $name$) {\n"
|
||||
" if (has_$oneof_name$()) {\n"
|
||||
" clear_$oneof_name$();\n"
|
||||
" }\n"
|
||||
" if ($name$ != nullptr) {\n"
|
||||
" set_has_$name$();\n"
|
||||
" $field$.InitAllocated($name$, GetArenaForAllocation());\n"
|
||||
" }\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void StringOneofFieldGenerator::GenerateClearingCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$.Destroy();\n");
|
||||
}
|
||||
|
||||
void StringOneofFieldGenerator::GenerateMessageClearingCode(
|
||||
io::Printer* printer) const {
|
||||
return GenerateClearingCode(printer);
|
||||
}
|
||||
|
||||
void StringOneofFieldGenerator::GenerateSwappingCode(
|
||||
io::Printer* printer) const {
|
||||
// Don't print any swapping code. Swapping the union will swap this field.
|
||||
}
|
||||
|
||||
void StringOneofFieldGenerator::GenerateConstructorCode(
|
||||
io::Printer* printer) const {
|
||||
// Nothing required here.
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedStringFieldGenerator::RepeatedStringFieldGenerator(
|
||||
const FieldDescriptor* descriptor, const Options& options)
|
||||
: FieldGenerator(descriptor, options) {
|
||||
SetStringVariables(descriptor, &variables_, options);
|
||||
}
|
||||
|
||||
RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {}
|
||||
|
||||
void RepeatedStringFieldGenerator::GeneratePrivateMembers(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("::$proto_ns$::RepeatedPtrField<std::string> $name$_;\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::GenerateAccessorDeclarations(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
// See comment above about unknown ctypes.
|
||||
bool unknown_ctype = descriptor_->options().ctype() !=
|
||||
EffectiveStringCType(descriptor_, options_);
|
||||
|
||||
if (unknown_ctype) {
|
||||
format.Outdent();
|
||||
format(
|
||||
" private:\n"
|
||||
" // Hidden due to unknown ctype option.\n");
|
||||
format.Indent();
|
||||
}
|
||||
|
||||
format(
|
||||
"$deprecated_attr$const std::string& ${1$$name$$}$(int index) const;\n"
|
||||
"$deprecated_attr$std::string* ${1$mutable_$name$$}$(int index);\n"
|
||||
"$deprecated_attr$void ${1$set_$name$$}$(int index, const "
|
||||
"std::string& value);\n"
|
||||
"$deprecated_attr$void ${1$set_$name$$}$(int index, std::string&& "
|
||||
"value);\n"
|
||||
"$deprecated_attr$void ${1$set_$name$$}$(int index, const "
|
||||
"char* value);\n",
|
||||
descriptor_);
|
||||
if (!options_.opensource_runtime) {
|
||||
format(
|
||||
"$deprecated_attr$void ${1$set_$name$$}$(int index, "
|
||||
"absl::string_view value);\n",
|
||||
descriptor_);
|
||||
}
|
||||
format(
|
||||
"$deprecated_attr$void ${1$set_$name$$}$("
|
||||
"int index, const $pointer_type$* value, size_t size);\n"
|
||||
"$deprecated_attr$std::string* ${1$add_$name$$}$();\n"
|
||||
"$deprecated_attr$void ${1$add_$name$$}$(const std::string& value);\n"
|
||||
"$deprecated_attr$void ${1$add_$name$$}$(std::string&& value);\n"
|
||||
"$deprecated_attr$void ${1$add_$name$$}$(const char* value);\n",
|
||||
descriptor_);
|
||||
if (!options_.opensource_runtime) {
|
||||
format(
|
||||
"$deprecated_attr$void ${1$add_$name$$}$(absl::string_view value);\n",
|
||||
descriptor_);
|
||||
}
|
||||
format(
|
||||
"$deprecated_attr$void ${1$add_$name$$}$(const $pointer_type$* "
|
||||
"value, size_t size)"
|
||||
";\n"
|
||||
"$deprecated_attr$const ::$proto_ns$::RepeatedPtrField<std::string>& "
|
||||
"${1$$name$$}$() "
|
||||
"const;\n"
|
||||
"$deprecated_attr$::$proto_ns$::RepeatedPtrField<std::string>* "
|
||||
"${1$mutable_$name$$}$()"
|
||||
";\n"
|
||||
"private:\n"
|
||||
"const std::string& ${1$_internal_$name$$}$(int index) const;\n"
|
||||
"std::string* _internal_add_$name$();\n"
|
||||
"public:\n",
|
||||
descriptor_);
|
||||
|
||||
if (unknown_ctype) {
|
||||
format.Outdent();
|
||||
format(" public:\n");
|
||||
format.Indent();
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"inline std::string* $classname$::add_$name$() {\n"
|
||||
" std::string* _s = _internal_add_$name$();\n"
|
||||
"$annotate_add_mutable$"
|
||||
" // @@protoc_insertion_point(field_add_mutable:$full_name$)\n"
|
||||
" return _s;\n"
|
||||
"}\n");
|
||||
if (options_.safe_boundary_check) {
|
||||
format(
|
||||
"inline const std::string& $classname$::_internal_$name$(int index) "
|
||||
"const {\n"
|
||||
" return $field$.InternalCheckedGet(\n"
|
||||
" index, ::$proto_ns$::internal::GetEmptyStringAlreadyInited());\n"
|
||||
"}\n");
|
||||
} else {
|
||||
format(
|
||||
"inline const std::string& $classname$::_internal_$name$(int index) "
|
||||
"const {\n"
|
||||
" return $field$.Get(index);\n"
|
||||
"}\n");
|
||||
}
|
||||
format(
|
||||
"inline const std::string& $classname$::$name$(int index) const {\n"
|
||||
"$annotate_get$"
|
||||
" // @@protoc_insertion_point(field_get:$full_name$)\n"
|
||||
" return _internal_$name$(index);\n"
|
||||
"}\n"
|
||||
"inline std::string* $classname$::mutable_$name$(int index) {\n"
|
||||
"$annotate_mutable$"
|
||||
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
|
||||
" return $field$.Mutable(index);\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$(int index, const std::string& "
|
||||
"value) "
|
||||
"{\n"
|
||||
" $field$.Mutable(index)->assign(value);\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set:$full_name$)\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$(int index, std::string&& value) {\n"
|
||||
" $field$.Mutable(index)->assign(std::move(value));\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set:$full_name$)\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$(int index, const char* value) {\n"
|
||||
" $DCHK$(value != nullptr);"
|
||||
" $field$.Mutable(index)->assign(value);\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set_char:$full_name$)\n"
|
||||
"}\n");
|
||||
if (!options_.opensource_runtime) {
|
||||
format(
|
||||
"inline void "
|
||||
"$classname$::set_$name$(int index, absl::string_view value) {\n"
|
||||
" $field$.Mutable(index)->assign(value.data(), value.size());\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n"
|
||||
"}\n");
|
||||
}
|
||||
format(
|
||||
"inline void "
|
||||
"$classname$::set_$name$"
|
||||
"(int index, const $pointer_type$* value, size_t size) {\n"
|
||||
" $field$.Mutable(index)->assign(\n"
|
||||
" reinterpret_cast<const char*>(value), size);\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
|
||||
"}\n"
|
||||
"inline std::string* $classname$::_internal_add_$name$() {\n"
|
||||
" return $field$.Add();\n"
|
||||
"}\n"
|
||||
"inline void $classname$::add_$name$(const std::string& value) {\n"
|
||||
" $field$.Add()->assign(value);\n"
|
||||
"$annotate_add$"
|
||||
" // @@protoc_insertion_point(field_add:$full_name$)\n"
|
||||
"}\n"
|
||||
"inline void $classname$::add_$name$(std::string&& value) {\n"
|
||||
" $field$.Add(std::move(value));\n"
|
||||
"$annotate_add$"
|
||||
" // @@protoc_insertion_point(field_add:$full_name$)\n"
|
||||
"}\n"
|
||||
"inline void $classname$::add_$name$(const char* value) {\n"
|
||||
" $DCHK$(value != nullptr);"
|
||||
" $field$.Add()->assign(value);\n"
|
||||
"$annotate_add$"
|
||||
" // @@protoc_insertion_point(field_add_char:$full_name$)\n"
|
||||
"}\n");
|
||||
if (!options_.opensource_runtime) {
|
||||
format(
|
||||
"inline void $classname$::add_$name$(absl::string_view value) {\n"
|
||||
" $field$.Add()->assign(value.data(), value.size());\n"
|
||||
"$annotate_add$"
|
||||
" // @@protoc_insertion_point(field_add_string_piece:$full_name$)\n"
|
||||
"}\n");
|
||||
}
|
||||
format(
|
||||
"inline void "
|
||||
"$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n"
|
||||
" $field$.Add()->assign(reinterpret_cast<const char*>(value), size);\n"
|
||||
"$annotate_add$"
|
||||
" // @@protoc_insertion_point(field_add_pointer:$full_name$)\n"
|
||||
"}\n"
|
||||
"inline const ::$proto_ns$::RepeatedPtrField<std::string>&\n"
|
||||
"$classname$::$name$() const {\n"
|
||||
"$annotate_list$"
|
||||
" // @@protoc_insertion_point(field_list:$full_name$)\n"
|
||||
" return $field$;\n"
|
||||
"}\n"
|
||||
"inline ::$proto_ns$::RepeatedPtrField<std::string>*\n"
|
||||
"$classname$::mutable_$name$() {\n"
|
||||
"$annotate_mutable_list$"
|
||||
" // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
|
||||
" return &$field$;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::GenerateClearingCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$.Clear();\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::GenerateMergingCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("_this->$field$.MergeFrom(from.$field$);\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::GenerateSwappingCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$.InternalSwap(&other->$field$);\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::GenerateDestructorCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$.~RepeatedPtrField();\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n"
|
||||
" const auto& s = this->_internal_$name$(i);\n");
|
||||
// format("for (const std::string& s : this->$name$()) {\n");
|
||||
format.Indent();
|
||||
if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
|
||||
GenerateUtf8CheckCodeForString(descriptor_, options_, false,
|
||||
"s.data(), static_cast<int>(s.length()),\n",
|
||||
format);
|
||||
}
|
||||
format.Outdent();
|
||||
format(
|
||||
" target = stream->Write$declared_type$($number$, s, target);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::GenerateByteSize(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"total_size += $tag_size$ *\n"
|
||||
" ::$proto_ns$::internal::FromIntSize($field$.size());\n"
|
||||
"for (int i = 0, n = $field$.size(); i < n; i++) {\n"
|
||||
" total_size += "
|
||||
"::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n"
|
||||
" $field$.Get(i));\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
136
libs/protobuf/src/google/protobuf/compiler/cpp/string_field.h
Normal file
136
libs/protobuf/src/google/protobuf/compiler/cpp/string_field.h
Normal file
@@ -0,0 +1,136 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "google/protobuf/compiler/cpp/field.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
class StringFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
StringFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options);
|
||||
StringFieldGenerator(const StringFieldGenerator&) = delete;
|
||||
StringFieldGenerator& operator=(const StringFieldGenerator&) = delete;
|
||||
~StringFieldGenerator() override;
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const override;
|
||||
void GenerateStaticMembers(io::Printer* printer) const override;
|
||||
void GenerateAccessorDeclarations(io::Printer* printer) const override;
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
|
||||
void GenerateNonInlineAccessorDefinitions(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateClearingCode(io::Printer* printer) const override;
|
||||
void GenerateMessageClearingCode(io::Printer* printer) const override;
|
||||
void GenerateMergingCode(io::Printer* printer) const override;
|
||||
void GenerateSwappingCode(io::Printer* printer) const override;
|
||||
void GenerateConstructorCode(io::Printer* printer) const override;
|
||||
void GenerateCopyConstructorCode(io::Printer* printer) const override;
|
||||
void GenerateDestructorCode(io::Printer* printer) const override;
|
||||
void GenerateArenaDestructorCode(io::Printer* printer) const override;
|
||||
void GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateByteSize(io::Printer* printer) const override;
|
||||
void GenerateConstexprAggregateInitializer(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateAggregateInitializer(io::Printer* printer) const override;
|
||||
void GenerateCopyAggregateInitializer(io::Printer* printer) const override;
|
||||
bool IsInlined() const override { return inlined_; }
|
||||
ArenaDtorNeeds NeedsArenaDestructor() const override;
|
||||
|
||||
private:
|
||||
bool inlined_;
|
||||
};
|
||||
|
||||
class StringOneofFieldGenerator : public StringFieldGenerator {
|
||||
public:
|
||||
StringOneofFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options);
|
||||
StringOneofFieldGenerator(const StringOneofFieldGenerator&) = delete;
|
||||
StringOneofFieldGenerator& operator=(const StringOneofFieldGenerator&) =
|
||||
delete;
|
||||
~StringOneofFieldGenerator() override;
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
|
||||
void GenerateClearingCode(io::Printer* printer) const override;
|
||||
|
||||
// StringFieldGenerator, from which we inherit, overrides this so we need to
|
||||
// override it as well.
|
||||
void GenerateMessageClearingCode(io::Printer* printer) const override;
|
||||
void GenerateSwappingCode(io::Printer* printer) const override;
|
||||
void GenerateConstructorCode(io::Printer* printer) const override;
|
||||
};
|
||||
|
||||
class RepeatedStringFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
|
||||
const Options& options);
|
||||
RepeatedStringFieldGenerator(const RepeatedStringFieldGenerator&) = delete;
|
||||
RepeatedStringFieldGenerator& operator=(const RepeatedStringFieldGenerator&) =
|
||||
delete;
|
||||
~RepeatedStringFieldGenerator() override;
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const override;
|
||||
void GenerateAccessorDeclarations(io::Printer* printer) const override;
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
|
||||
void GenerateClearingCode(io::Printer* printer) const override;
|
||||
void GenerateMergingCode(io::Printer* printer) const override;
|
||||
void GenerateSwappingCode(io::Printer* printer) const override;
|
||||
void GenerateConstructorCode(io::Printer* printer) const override {}
|
||||
void GenerateCopyConstructorCode(io::Printer* /*printer*/) const override {
|
||||
GOOGLE_CHECK(!ShouldSplit(descriptor_, options_));
|
||||
}
|
||||
void GenerateDestructorCode(io::Printer* printer) const override;
|
||||
void GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const override;
|
||||
void GenerateByteSize(io::Printer* printer) const override;
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__
|
||||
@@ -0,0 +1,186 @@
|
||||
// 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.
|
||||
//
|
||||
// This file tests that various identifiers work as field and type names even
|
||||
// though the same identifiers are used internally by the C++ code generator.
|
||||
|
||||
// LINT: LEGACY_NAMES
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
// Some generic_services option(s) added automatically.
|
||||
// See: http://go/proto2-generic-services-default
|
||||
option cc_generic_services = true; // auto-added
|
||||
|
||||
// We don't put this in a package within proto2 because we need to make sure
|
||||
// that the generated code doesn't depend on being in the proto2 namespace.
|
||||
package protobuf_unittest;
|
||||
|
||||
// Test that fields can have names like "input" and "i" which are also used
|
||||
// internally by the code generator for local variables.
|
||||
message TestConflictingSymbolNames {
|
||||
message BuildDescriptors {}
|
||||
message TypeTraits {}
|
||||
|
||||
optional int32 input = 1;
|
||||
optional int32 output = 2;
|
||||
optional string length = 3;
|
||||
repeated int32 i = 4;
|
||||
repeated string new_element = 5 [ctype = STRING_PIECE];
|
||||
optional int32 total_size = 6;
|
||||
optional int32 tag = 7;
|
||||
|
||||
enum TestEnum {
|
||||
FOO = 0;
|
||||
}
|
||||
message Data1 {
|
||||
repeated int32 data = 1;
|
||||
}
|
||||
message Data2 {
|
||||
repeated TestEnum data = 1;
|
||||
}
|
||||
message Data3 {
|
||||
repeated string data = 1;
|
||||
}
|
||||
message Data4 {
|
||||
repeated Data4 data = 1;
|
||||
}
|
||||
message Data5 {
|
||||
repeated string data = 1 [ctype = STRING_PIECE];
|
||||
}
|
||||
message Data6 {
|
||||
repeated string data = 1 [ctype = CORD];
|
||||
}
|
||||
|
||||
optional int32 source = 8;
|
||||
optional int32 value = 9;
|
||||
optional int32 file = 10;
|
||||
optional int32 from = 11;
|
||||
optional int32 handle_uninterpreted = 12;
|
||||
repeated int32 index = 13;
|
||||
optional int32 controller = 14;
|
||||
optional int32 already_here = 15;
|
||||
|
||||
optional uint32 uint32 = 16;
|
||||
optional uint64 uint64 = 17;
|
||||
optional string string = 18;
|
||||
optional int32 memset = 19;
|
||||
optional int32 int32 = 20;
|
||||
optional int64 int64 = 21;
|
||||
|
||||
optional uint32 cached_size = 22;
|
||||
optional uint32 extensions = 23;
|
||||
optional uint32 bit = 24;
|
||||
optional uint32 bits = 25;
|
||||
optional uint32 offsets = 26;
|
||||
optional uint32 reflection = 27;
|
||||
|
||||
message Cord {}
|
||||
optional string some_cord = 28 [ctype = CORD];
|
||||
|
||||
message StringPiece {}
|
||||
optional string some_string_piece = 29 [ctype = STRING_PIECE];
|
||||
|
||||
// Some keywords.
|
||||
optional uint32 int = 30;
|
||||
optional uint32 friend = 31;
|
||||
optional uint32 class = 37;
|
||||
optional uint32 typedecl = 39;
|
||||
optional uint32 auto = 40;
|
||||
|
||||
// The generator used to #define a macro called "DO" inside the .cc file.
|
||||
message DO {}
|
||||
optional DO do = 32;
|
||||
|
||||
// Some template parameter names for extensions.
|
||||
optional int32 field_type = 33;
|
||||
optional bool is_packed = 34;
|
||||
|
||||
// test conflicting release_$name$. "length" and "do" field in this message
|
||||
// must remain string or message fields to make the test valid.
|
||||
optional string release_length = 35;
|
||||
// A more extreme case, the field name "do" here is a keyword, which will be
|
||||
// escaped to "do_" already. Test there is no conflict even with escaped field
|
||||
// names.
|
||||
optional DO release_do = 36;
|
||||
|
||||
// For clashing local variables in Serialize and ByteSize calculation.
|
||||
optional string target = 38;
|
||||
|
||||
extensions 1000 to max; // NO_PROTO3
|
||||
}
|
||||
|
||||
message TestConflictingSymbolNamesExtension { // NO_PROTO3
|
||||
extend TestConflictingSymbolNames { // NO_PROTO3
|
||||
repeated int32 repeated_int32_ext = 20423638 [packed = true]; // NO_PROTO3
|
||||
} // NO_PROTO3
|
||||
} // NO_PROTO3
|
||||
|
||||
message TestConflictingEnumNames { // NO_PROTO3
|
||||
enum while { // NO_PROTO3
|
||||
default = 0; // NO_PROTO3
|
||||
and = 1; // NO_PROTO3
|
||||
class = 2; // NO_PROTO3
|
||||
int = 3; // NO_PROTO3
|
||||
typedef = 4; // NO_PROTO3
|
||||
XOR = 5; // NO_PROTO3
|
||||
} // NO_PROTO3
|
||||
|
||||
optional while conflicting_enum = 1; // NO_PROTO3
|
||||
} // NO_PROTO3
|
||||
|
||||
enum bool { // NO_PROTO3
|
||||
default = 0; // NO_PROTO3
|
||||
NOT_EQ = 1; // NO_PROTO3
|
||||
volatile = 2; // NO_PROTO3
|
||||
return = 3; // NO_PROTO3
|
||||
} // NO_PROTO3
|
||||
|
||||
message DummyMessage {}
|
||||
|
||||
message NULL {
|
||||
optional int32 int = 1;
|
||||
}
|
||||
|
||||
extend TestConflictingSymbolNames { // NO_PROTO3
|
||||
optional int32 void = 314253; // NO_PROTO3
|
||||
} // NO_PROTO3
|
||||
|
||||
// Message names that could conflict.
|
||||
message Shutdown {}
|
||||
message TableStruct {}
|
||||
|
||||
service TestConflictingMethodNames {
|
||||
rpc Closure(DummyMessage) returns (DummyMessage);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// 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.
|
||||
|
||||
// Test that proto2 compiler can generate valid code when the enum value
|
||||
// is INT_MAX. Note that this is a compile-only test and this proto is not
|
||||
// referenced in any C++ code.
|
||||
syntax = "proto2";
|
||||
|
||||
package protobuf_unittest;
|
||||
|
||||
message TestLargeEnumValue {
|
||||
enum EnumWithLargeValue {
|
||||
VALUE_1 = 1;
|
||||
VALUE_MAX = 0x7fffffff;
|
||||
}
|
||||
}
|
||||
133
libs/protobuf/src/google/protobuf/compiler/cpp/unittest.cc
Normal file
133
libs/protobuf/src/google/protobuf/compiler/cpp/unittest.cc
Normal file
@@ -0,0 +1,133 @@
|
||||
// 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.
|
||||
//
|
||||
// To test the code generator, we actually use it to generate code for
|
||||
// net/proto2/internal/unittest.proto, then test that. This means that we
|
||||
// are actually testing the parser and other parts of the system at the same
|
||||
// time, and that problems in the generator may show up as compile-time errors
|
||||
// rather than unittest failures, which may be surprising. However, testing
|
||||
// the output of the C++ generator directly would be very hard. We can't very
|
||||
// well just check it against golden files since those files would have to be
|
||||
// updated for any small change; such a test would be very brittle and probably
|
||||
// not very helpful. What we really want to test is that the code compiles
|
||||
// correctly and produces the interfaces we expect, which is why this test
|
||||
// is written this way.
|
||||
|
||||
#include "google/protobuf/compiler/cpp/unittest.h"
|
||||
|
||||
#include "google/protobuf/unittest.pb.h"
|
||||
#include "google/protobuf/unittest_embed_optimize_for.pb.h"
|
||||
#include "google/protobuf/unittest_optimize_for.pb.h"
|
||||
#include "google/protobuf/test_util.h"
|
||||
|
||||
#define MESSAGE_TEST_NAME MessageTest
|
||||
#define GENERATED_DESCRIPTOR_TEST_NAME GeneratedDescriptorTest
|
||||
#define GENERATED_MESSAGE_TEST_NAME GeneratedMessageTest
|
||||
#define GENERATED_ENUM_TEST_NAME GeneratedEnumTest
|
||||
#define GENERATED_SERVICE_TEST_NAME GeneratedServiceTest
|
||||
#define HELPERS_TEST_NAME HelpersTest
|
||||
#define DESCRIPTOR_INIT_TEST_NAME DescriptorInitializationTest
|
||||
|
||||
#define UNITTEST_PROTO_PATH "net/proto2/internal/unittest.proto"
|
||||
#define UNITTEST ::protobuf_unittest
|
||||
#define UNITTEST_IMPORT ::protobuf_unittest_import
|
||||
|
||||
// Must include after the above macros.
|
||||
#include "google/protobuf/compiler/cpp/unittest.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
|
||||
namespace cpp_unittest {
|
||||
|
||||
namespace protobuf_unittest = ::protobuf_unittest;
|
||||
|
||||
TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingSymbolNames) {
|
||||
// test_bad_identifiers.proto successfully compiled, then it works. The
|
||||
// following is just a token usage to insure that the code is, in fact,
|
||||
// being compiled and linked.
|
||||
|
||||
protobuf_unittest::TestConflictingSymbolNames message;
|
||||
message.set_uint32(1);
|
||||
EXPECT_EQ(3, message.ByteSizeLong());
|
||||
|
||||
message.set_friend_(5);
|
||||
EXPECT_EQ(5, message.friend_());
|
||||
|
||||
message.set_class_(6);
|
||||
EXPECT_EQ(6, message.class_());
|
||||
|
||||
// Instantiate extension template functions to test conflicting template
|
||||
// parameter names.
|
||||
typedef protobuf_unittest::TestConflictingSymbolNamesExtension ExtensionMessage;
|
||||
message.AddExtension(ExtensionMessage::repeated_int32_ext, 123);
|
||||
EXPECT_EQ(123, message.GetExtension(ExtensionMessage::repeated_int32_ext, 0));
|
||||
}
|
||||
|
||||
TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingEnumNames) {
|
||||
protobuf_unittest::TestConflictingEnumNames message;
|
||||
message.set_conflicting_enum(
|
||||
protobuf_unittest::TestConflictingEnumNames_while_and_);
|
||||
EXPECT_EQ(1, message.conflicting_enum());
|
||||
message.set_conflicting_enum(
|
||||
protobuf_unittest::TestConflictingEnumNames_while_XOR);
|
||||
EXPECT_EQ(5, message.conflicting_enum());
|
||||
|
||||
protobuf_unittest::bool_ conflicting_enum;
|
||||
conflicting_enum = protobuf_unittest::NOT_EQ;
|
||||
EXPECT_EQ(1, conflicting_enum);
|
||||
conflicting_enum = protobuf_unittest::return_;
|
||||
EXPECT_EQ(3, conflicting_enum);
|
||||
}
|
||||
|
||||
TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingMessageNames) {
|
||||
protobuf_unittest::NULL_ message;
|
||||
message.set_int_(123);
|
||||
EXPECT_EQ(message.int_(), 123);
|
||||
}
|
||||
|
||||
TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingExtension) {
|
||||
protobuf_unittest::TestConflictingSymbolNames message;
|
||||
message.SetExtension(protobuf_unittest::void_, 123);
|
||||
EXPECT_EQ(123, message.GetExtension(protobuf_unittest::void_));
|
||||
}
|
||||
|
||||
} // namespace cpp_unittest
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
51
libs/protobuf/src/google/protobuf/compiler/cpp/unittest.h
Normal file
51
libs/protobuf/src/google/protobuf/compiler/cpp/unittest.h
Normal file
@@ -0,0 +1,51 @@
|
||||
// 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.
|
||||
|
||||
// This header declares the namespace google::protobuf::protobuf_unittest in order to expose
|
||||
// any problems with the generated class names. We use this header to ensure
|
||||
// unittest.cc will declare the namespace prior to other includes, while obeying
|
||||
// normal include ordering.
|
||||
//
|
||||
// When generating a class name of "foo.Bar" we must ensure we prefix the class
|
||||
// name with "::", in case the namespace google::protobuf::foo exists. We intentionally
|
||||
// trigger that case here by declaring google::protobuf::protobuf_unittest.
|
||||
//
|
||||
// See ClassName in helpers.h for more details.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace protobuf_unittest {}
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__
|
||||
2224
libs/protobuf/src/google/protobuf/compiler/cpp/unittest.inc
Normal file
2224
libs/protobuf/src/google/protobuf/compiler/cpp/unittest.inc
Normal file
File diff suppressed because it is too large
Load Diff
133
libs/protobuf/src/google/protobuf/compiler/csharp/BUILD.bazel
Normal file
133
libs/protobuf/src/google/protobuf/compiler/csharp/BUILD.bazel
Normal file
@@ -0,0 +1,133 @@
|
||||
################################################################################
|
||||
# Protocol Buffers Compiler - C# code generator
|
||||
################################################################################
|
||||
|
||||
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
|
||||
load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
|
||||
load("//build_defs:cpp_opts.bzl", "COPTS")
|
||||
|
||||
cc_library(
|
||||
name = "names",
|
||||
hdrs = ["names.h"],
|
||||
srcs = ["names.cc"],
|
||||
copts = COPTS,
|
||||
include_prefix = "google/protobuf/compiler/csharp",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//src/google/protobuf:protobuf_nowkt",
|
||||
"@com_google_absl//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "csharp",
|
||||
srcs = [
|
||||
"csharp_doc_comment.cc",
|
||||
"csharp_enum.cc",
|
||||
"csharp_enum_field.cc",
|
||||
"csharp_field_base.cc",
|
||||
"csharp_generator.cc",
|
||||
"csharp_helpers.cc",
|
||||
"csharp_map_field.cc",
|
||||
"csharp_message.cc",
|
||||
"csharp_message_field.cc",
|
||||
"csharp_primitive_field.cc",
|
||||
"csharp_reflection_class.cc",
|
||||
"csharp_repeated_enum_field.cc",
|
||||
"csharp_repeated_message_field.cc",
|
||||
"csharp_repeated_primitive_field.cc",
|
||||
"csharp_source_generator_base.cc",
|
||||
"csharp_wrapper_field.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"csharp_doc_comment.h",
|
||||
"csharp_enum.h",
|
||||
"csharp_enum_field.h",
|
||||
"csharp_field_base.h",
|
||||
"csharp_generator.h",
|
||||
"csharp_helpers.h",
|
||||
"csharp_map_field.h",
|
||||
"csharp_message.h",
|
||||
"csharp_message_field.h",
|
||||
"csharp_options.h",
|
||||
"csharp_primitive_field.h",
|
||||
"csharp_reflection_class.h",
|
||||
"csharp_repeated_enum_field.h",
|
||||
"csharp_repeated_message_field.h",
|
||||
"csharp_repeated_primitive_field.h",
|
||||
"csharp_source_generator_base.h",
|
||||
"csharp_wrapper_field.h",
|
||||
],
|
||||
copts = COPTS + select({
|
||||
"//build_defs:config_msvc": [],
|
||||
"//conditions:default": ["-Wno-overloaded-virtual"],
|
||||
}),
|
||||
include_prefix = "google/protobuf/compiler/csharp",
|
||||
visibility = [
|
||||
"//pkg:__pkg__",
|
||||
"//src/google/protobuf/compiler:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
":names",
|
||||
"//src/google/protobuf:protobuf_nowkt",
|
||||
"//src/google/protobuf/compiler:code_generator",
|
||||
"@com_google_absl//absl/container:flat_hash_set",
|
||||
"@com_google_absl//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "bootstrap_unittest",
|
||||
srcs = ["csharp_bootstrap_unittest.cc"],
|
||||
data = [
|
||||
"//:well_known_type_protos",
|
||||
"//conformance:all_files",
|
||||
"//conformance:conformance_proto",
|
||||
"//csharp:wkt_cs_srcs",
|
||||
"//src/google/protobuf:descriptor_proto_srcs",
|
||||
"//src/google/protobuf:testdata",
|
||||
],
|
||||
deps = [
|
||||
":csharp",
|
||||
"//:protobuf",
|
||||
"//src/google/protobuf/compiler:importer",
|
||||
"//src/google/protobuf/io",
|
||||
"//src/google/protobuf/stubs",
|
||||
"//src/google/protobuf/testing",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "generator_unittest",
|
||||
srcs = ["csharp_generator_unittest.cc"],
|
||||
deps = [
|
||||
":csharp",
|
||||
"//:protobuf",
|
||||
"//src/google/protobuf/compiler:command_line_interface",
|
||||
"//src/google/protobuf/io",
|
||||
"@com_google_googletest//:gtest",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
################################################################################
|
||||
# Distribution packaging
|
||||
################################################################################
|
||||
|
||||
pkg_files(
|
||||
name = "dist_files",
|
||||
srcs = glob(["**/*"]),
|
||||
strip_prefix = strip_prefix.from_root(""),
|
||||
visibility = ["//src:__pkg__"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "test_srcs",
|
||||
srcs = glob([
|
||||
"*_test.cc",
|
||||
"*unittest.cc",
|
||||
]),
|
||||
visibility = ["//src/google/protobuf/compiler:__pkg__"],
|
||||
)
|
||||
@@ -0,0 +1,188 @@
|
||||
// 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.
|
||||
|
||||
// This test insures that
|
||||
// csharp/src/Google.Protobuf/Reflection/Descriptor.cs match exactly
|
||||
// what would be generated by the protocol compiler. The file is not
|
||||
// generated automatically at build time.
|
||||
//
|
||||
// If this test fails, run the script
|
||||
// "generate_descriptor_proto.sh" and add the changed files under
|
||||
// csharp/src/ to your changelist.
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "google/protobuf/testing/file.h"
|
||||
#include "google/protobuf/testing/googletest.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include "absl/strings/ascii.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/strings/str_replace.h"
|
||||
#include "absl/strings/str_split.h"
|
||||
#include "absl/strings/substitute.h"
|
||||
#include "google/protobuf/compiler/csharp/csharp_generator.h"
|
||||
#include "google/protobuf/compiler/importer.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/io/zero_copy_stream_impl.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace csharp {
|
||||
|
||||
namespace {
|
||||
|
||||
class MockErrorCollector : public MultiFileErrorCollector {
|
||||
public:
|
||||
MockErrorCollector() {}
|
||||
~MockErrorCollector() {}
|
||||
|
||||
std::string text_;
|
||||
|
||||
// implements ErrorCollector ---------------------------------------
|
||||
void AddError(const std::string& filename, int line, int column,
|
||||
const std::string& message) {
|
||||
absl::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", filename, line, column,
|
||||
message);
|
||||
}
|
||||
};
|
||||
|
||||
class MockGeneratorContext : public GeneratorContext {
|
||||
public:
|
||||
void ExpectFileMatches(const std::string& virtual_filename,
|
||||
const std::string& physical_filename) {
|
||||
auto it = files_.find(virtual_filename);
|
||||
ASSERT_TRUE(it != files_.end())
|
||||
<< "Generator failed to generate file: " << virtual_filename;
|
||||
std::string expected_contents = *it->second;
|
||||
|
||||
std::string actual_contents;
|
||||
GOOGLE_CHECK_OK(
|
||||
File::GetContentsAsText(TestSourceDir() + "/" + physical_filename,
|
||||
&actual_contents, true))
|
||||
<< "Unable to get " << physical_filename;
|
||||
EXPECT_TRUE(actual_contents == expected_contents)
|
||||
<< physical_filename << " needs to be regenerated. Please run "
|
||||
"generate_descriptor_proto.sh. Then add this file "
|
||||
"to your CL.";
|
||||
}
|
||||
|
||||
// implements GeneratorContext --------------------------------------
|
||||
|
||||
virtual io::ZeroCopyOutputStream* Open(const std::string& filename) {
|
||||
auto& map_slot = files_[filename];
|
||||
map_slot.reset(new std::string);
|
||||
return new io::StringOutputStream(map_slot.get());
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<std::string, std::unique_ptr<std::string>> files_;
|
||||
};
|
||||
|
||||
class GenerateAndTest {
|
||||
public:
|
||||
GenerateAndTest() {}
|
||||
void Run(const FileDescriptor* proto_file, std::string file1,
|
||||
std::string file2) {
|
||||
ASSERT_TRUE(proto_file != NULL) << TestSourceDir();
|
||||
ASSERT_TRUE(generator_.Generate(proto_file, parameter_,
|
||||
&context_, &error_));
|
||||
context_.ExpectFileMatches(file1, file2);
|
||||
}
|
||||
void SetParameter(std::string parameter) {
|
||||
parameter_ = parameter;
|
||||
}
|
||||
|
||||
private:
|
||||
Generator generator_;
|
||||
MockGeneratorContext context_;
|
||||
std::string error_;
|
||||
std::string parameter_;
|
||||
};
|
||||
|
||||
TEST(CsharpBootstrapTest, GeneratedCsharpDescriptorMatches) {
|
||||
// Skip this whole test if the csharp directory doesn't exist (i.e., a C++11
|
||||
// only distribution).
|
||||
std::string descriptor_file_name =
|
||||
"../csharp/src/Google.Protobuf/Reflection/Descriptor.cs";
|
||||
if (!File::Exists(TestSourceDir() + "/" + descriptor_file_name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MockErrorCollector error_collector;
|
||||
DiskSourceTree source_tree;
|
||||
Importer importer(&source_tree, &error_collector);
|
||||
GenerateAndTest generate_test;
|
||||
|
||||
generate_test.SetParameter("base_namespace=Google.Protobuf");
|
||||
source_tree.MapPath("", TestSourceDir());
|
||||
generate_test.Run(importer.Import("google/protobuf/descriptor.proto"),
|
||||
"Reflection/Descriptor.cs",
|
||||
"../csharp/src/Google.Protobuf/Reflection/Descriptor.cs");
|
||||
generate_test.Run(importer.Import("google/protobuf/any.proto"),
|
||||
"WellKnownTypes/Any.cs",
|
||||
"../csharp/src/Google.Protobuf/WellKnownTypes/Any.cs");
|
||||
generate_test.Run(importer.Import("google/protobuf/api.proto"),
|
||||
"WellKnownTypes/Api.cs",
|
||||
"../csharp/src/Google.Protobuf/WellKnownTypes/Api.cs");
|
||||
generate_test.Run(importer.Import("google/protobuf/duration.proto"),
|
||||
"WellKnownTypes/Duration.cs",
|
||||
"../csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs");
|
||||
generate_test.Run(importer.Import("google/protobuf/empty.proto"),
|
||||
"WellKnownTypes/Empty.cs",
|
||||
"../csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs");
|
||||
generate_test.Run(importer.Import("google/protobuf/field_mask.proto"),
|
||||
"WellKnownTypes/FieldMask.cs",
|
||||
"../csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs");
|
||||
generate_test.Run(importer.Import("google/protobuf/source_context.proto"),
|
||||
"WellKnownTypes/SourceContext.cs",
|
||||
"../csharp/src/Google.Protobuf/WellKnownTypes/SourceContext.cs");
|
||||
generate_test.Run(importer.Import("google/protobuf/struct.proto"),
|
||||
"WellKnownTypes/Struct.cs",
|
||||
"../csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs");
|
||||
generate_test.Run(importer.Import("google/protobuf/timestamp.proto"),
|
||||
"WellKnownTypes/Timestamp.cs",
|
||||
"../csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs");
|
||||
generate_test.Run(importer.Import("google/protobuf/type.proto"),
|
||||
"WellKnownTypes/Type.cs",
|
||||
"../csharp/src/Google.Protobuf/WellKnownTypes/Type.cs");
|
||||
generate_test.Run(importer.Import("google/protobuf/wrappers.proto"),
|
||||
"WellKnownTypes/Wrappers.cs",
|
||||
"../csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs");
|
||||
|
||||
EXPECT_EQ("", error_collector.text_);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace csharp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
@@ -0,0 +1,117 @@
|
||||
// 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/compiler/csharp/csharp_doc_comment.h"
|
||||
|
||||
#include "absl/strings/str_replace.h"
|
||||
#include "absl/strings/str_split.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace csharp {
|
||||
|
||||
// Functions to create C# XML documentation comments.
|
||||
// Currently this only includes documentation comments containing text specified as comments
|
||||
// in the .proto file; documentation comments generated just from field/message/enum/proto names
|
||||
// is inlined in the relevant code. If more control is required, that code can be moved here.
|
||||
|
||||
void WriteDocCommentBodyImpl(io::Printer* printer, SourceLocation location) {
|
||||
std::string comments = location.leading_comments.empty() ?
|
||||
location.trailing_comments : location.leading_comments;
|
||||
if (comments.empty()) {
|
||||
return;
|
||||
}
|
||||
// XML escaping... no need for apostrophes etc as the whole text is going to be a child
|
||||
// node of a summary element, not part of an attribute.
|
||||
comments = absl::StrReplaceAll(comments, {{"&", "&"}, {"<", "<"}});
|
||||
std::vector<std::string> lines;
|
||||
lines = absl::StrSplit(comments, "\n", absl::AllowEmpty());
|
||||
// TODO: We really should work out which part to put in the summary and which to put in the remarks...
|
||||
// but that needs to be part of a bigger effort to understand the markdown better anyway.
|
||||
printer->Print("/// <summary>\n");
|
||||
bool last_was_empty = false;
|
||||
// We squash multiple blank lines down to one, and remove any trailing blank lines. We need
|
||||
// to preserve the blank lines themselves, as this is relevant in the markdown.
|
||||
// Note that we can't remove leading or trailing whitespace as *that's* relevant in markdown too.
|
||||
// (We don't skip "just whitespace" lines, either.)
|
||||
for (std::vector<std::string>::iterator it = lines.begin();
|
||||
it != lines.end(); ++it) {
|
||||
std::string line = *it;
|
||||
if (line.empty()) {
|
||||
last_was_empty = true;
|
||||
} else {
|
||||
if (last_was_empty) {
|
||||
printer->Print("///\n");
|
||||
}
|
||||
last_was_empty = false;
|
||||
printer->Print("///$line$\n", "line", *it);
|
||||
}
|
||||
}
|
||||
printer->Print("/// </summary>\n");
|
||||
}
|
||||
|
||||
template <typename DescriptorType>
|
||||
static void WriteDocCommentBody(
|
||||
io::Printer* printer, const DescriptorType* descriptor) {
|
||||
SourceLocation location;
|
||||
if (descriptor->GetSourceLocation(&location)) {
|
||||
WriteDocCommentBodyImpl(printer, location);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteMessageDocComment(io::Printer* printer, const Descriptor* message) {
|
||||
WriteDocCommentBody(printer, message);
|
||||
}
|
||||
|
||||
void WritePropertyDocComment(io::Printer* printer, const FieldDescriptor* field) {
|
||||
WriteDocCommentBody(printer, field);
|
||||
}
|
||||
|
||||
void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enumDescriptor) {
|
||||
WriteDocCommentBody(printer, enumDescriptor);
|
||||
}
|
||||
void WriteEnumValueDocComment(io::Printer* printer, const EnumValueDescriptor* value) {
|
||||
WriteDocCommentBody(printer, value);
|
||||
}
|
||||
|
||||
void WriteMethodDocComment(io::Printer* printer, const MethodDescriptor* method) {
|
||||
WriteDocCommentBody(printer, method);
|
||||
}
|
||||
|
||||
} // namespace csharp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
@@ -0,0 +1,51 @@
|
||||
// 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.
|
||||
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__
|
||||
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace csharp {
|
||||
void WriteMessageDocComment(io::Printer* printer, const Descriptor* message);
|
||||
void WritePropertyDocComment(io::Printer* printer, const FieldDescriptor* field);
|
||||
void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enumDescriptor);
|
||||
void WriteEnumValueDocComment(io::Printer* printer, const EnumValueDescriptor* value);
|
||||
void WriteMethodDocComment(io::Printer* printer, const MethodDescriptor* method);
|
||||
} // namespace csharp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_DOC_COMMENT_H__
|
||||
104
libs/protobuf/src/google/protobuf/compiler/csharp/csharp_enum.cc
Normal file
104
libs/protobuf/src/google/protobuf/compiler/csharp/csharp_enum.cc
Normal file
@@ -0,0 +1,104 @@
|
||||
// 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/compiler/csharp/csharp_enum.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "google/protobuf/compiler/code_generator.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "google/protobuf/compiler/csharp/csharp_doc_comment.h"
|
||||
#include "google/protobuf/compiler/csharp/csharp_helpers.h"
|
||||
#include "google/protobuf/compiler/csharp/csharp_options.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace csharp {
|
||||
|
||||
EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, const Options* options) :
|
||||
SourceGeneratorBase(options),
|
||||
descriptor_(descriptor) {
|
||||
}
|
||||
|
||||
EnumGenerator::~EnumGenerator() {
|
||||
}
|
||||
|
||||
void EnumGenerator::Generate(io::Printer* printer) {
|
||||
WriteEnumDocComment(printer, descriptor_);
|
||||
if (descriptor_->options().deprecated()) {
|
||||
printer->Print("[global::System.ObsoleteAttribute]\n");
|
||||
}
|
||||
printer->Print("$access_level$ enum $name$ {\n",
|
||||
"access_level", class_access_level(),
|
||||
"name", descriptor_->name());
|
||||
printer->Indent();
|
||||
std::set<std::string> used_names;
|
||||
std::set<int> used_number;
|
||||
for (int i = 0; i < descriptor_->value_count(); i++) {
|
||||
WriteEnumValueDocComment(printer, descriptor_->value(i));
|
||||
if (descriptor_->value(i)->options().deprecated()) {
|
||||
printer->Print("[global::System.ObsoleteAttribute]\n");
|
||||
}
|
||||
std::string original_name = descriptor_->value(i)->name();
|
||||
std::string name =
|
||||
GetEnumValueName(descriptor_->name(), descriptor_->value(i)->name());
|
||||
// Make sure we don't get any duplicate names due to prefix removal.
|
||||
while (!used_names.insert(name).second) {
|
||||
// It's possible we'll end up giving this warning multiple times, but that's better than not at all.
|
||||
GOOGLE_LOG(WARNING) << "Duplicate enum value " << name << " (originally " << original_name
|
||||
<< ") in " << descriptor_->name() << "; adding underscore to distinguish";
|
||||
name += "_";
|
||||
}
|
||||
int number = descriptor_->value(i)->number();
|
||||
if (!used_number.insert(number).second) {
|
||||
printer->Print("[pbr::OriginalName(\"$original_name$\", PreferredAlias = false)] $name$ = $number$,\n",
|
||||
"original_name", original_name,
|
||||
"name", name,
|
||||
"number", absl::StrCat(number));
|
||||
} else {
|
||||
printer->Print("[pbr::OriginalName(\"$original_name$\")] $name$ = $number$,\n",
|
||||
"original_name", original_name,
|
||||
"name", name,
|
||||
"number", absl::StrCat(number));
|
||||
}
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
printer->Print("\n");
|
||||
}
|
||||
|
||||
} // namespace csharp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
@@ -0,0 +1,66 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "google/protobuf/compiler/code_generator.h"
|
||||
#include "google/protobuf/compiler/csharp/csharp_source_generator_base.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace csharp {
|
||||
|
||||
class EnumGenerator : public SourceGeneratorBase {
|
||||
public:
|
||||
EnumGenerator(const EnumDescriptor* descriptor, const Options* options);
|
||||
~EnumGenerator();
|
||||
|
||||
EnumGenerator(const EnumGenerator&) = delete;
|
||||
EnumGenerator& operator=(const EnumGenerator&) = delete;
|
||||
|
||||
void Generate(io::Printer* printer);
|
||||
|
||||
private:
|
||||
const EnumDescriptor* descriptor_;
|
||||
};
|
||||
|
||||
} // namespace csharp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
// 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/compiler/csharp/csharp_enum_field.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "google/protobuf/compiler/code_generator.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/compiler/csharp/csharp_doc_comment.h"
|
||||
#include "google/protobuf/compiler/csharp/csharp_helpers.h"
|
||||
#include "google/protobuf/compiler/csharp/csharp_options.h"
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "google/protobuf/io/zero_copy_stream.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace csharp {
|
||||
|
||||
EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int presenceIndex, const Options *options)
|
||||
: PrimitiveFieldGenerator(descriptor, presenceIndex, options) {
|
||||
}
|
||||
|
||||
EnumFieldGenerator::~EnumFieldGenerator() {
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::GenerateParsingCode(io::Printer* printer) {
|
||||
printer->Print(variables_,
|
||||
"$property_name$ = ($type_name$) input.ReadEnum();\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
|
||||
printer->Print(variables_,
|
||||
"if ($has_property_check$) {\n"
|
||||
" output.WriteRawTag($tag_bytes$);\n"
|
||||
" output.WriteEnum((int) $property_name$);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"if ($has_property_check$) {\n"
|
||||
" size += $tag_size$ + pb::CodedOutputStream.ComputeEnumSize((int) $property_name$);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::GenerateCodecCode(io::Printer* printer) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"pb::FieldCodec.ForEnum($tag$, x => (int) x, x => ($type_name$) x, $default_value$)");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::GenerateExtensionCode(io::Printer* printer) {
|
||||
WritePropertyDocComment(printer, descriptor_);
|
||||
AddDeprecatedFlag(printer);
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$access_level$ static readonly pb::Extension<$extended_type$, $type_name$> $property_name$ =\n"
|
||||
" new pb::Extension<$extended_type$, $type_name$>($number$, ");
|
||||
GenerateCodecCode(printer);
|
||||
printer->Print(");\n");
|
||||
}
|
||||
|
||||
EnumOneofFieldGenerator::EnumOneofFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int presenceIndex, const Options *options)
|
||||
: PrimitiveOneofFieldGenerator(descriptor, presenceIndex, options) {
|
||||
}
|
||||
|
||||
EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {
|
||||
}
|
||||
|
||||
void EnumOneofFieldGenerator::GenerateMergingCode(io::Printer* printer) {
|
||||
printer->Print(variables_, "$property_name$ = other.$property_name$;\n");
|
||||
}
|
||||
|
||||
void EnumOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
|
||||
// TODO(jonskeet): What about if we read the default value?
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$oneof_name$_ = input.ReadEnum();\n"
|
||||
"$oneof_name$Case_ = $oneof_property_name$OneofCase.$oneof_case_name$;\n");
|
||||
}
|
||||
|
||||
void EnumOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"if ($has_property_check$) {\n"
|
||||
" output.WriteRawTag($tag_bytes$);\n"
|
||||
" output.WriteEnum((int) $property_name$);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void EnumOneofFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"if ($has_property_check$) {\n"
|
||||
" size += $tag_size$ + pb::CodedOutputStream.ComputeEnumSize((int) $property_name$);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
} // namespace csharp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
@@ -0,0 +1,81 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__
|
||||
|
||||
#include "google/protobuf/compiler/code_generator.h"
|
||||
#include "google/protobuf/compiler/csharp/csharp_primitive_field.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace csharp {
|
||||
|
||||
class EnumFieldGenerator : public PrimitiveFieldGenerator {
|
||||
public:
|
||||
EnumFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int presenceIndex,
|
||||
const Options *options);
|
||||
~EnumFieldGenerator();
|
||||
|
||||
EnumFieldGenerator(const EnumFieldGenerator&) = delete;
|
||||
EnumFieldGenerator& operator=(const EnumFieldGenerator&) = delete;
|
||||
|
||||
virtual void GenerateCodecCode(io::Printer* printer) override;
|
||||
virtual void GenerateParsingCode(io::Printer* printer) override;
|
||||
virtual void GenerateSerializationCode(io::Printer* printer) override;
|
||||
virtual void GenerateSerializedSizeCode(io::Printer* printer) override;
|
||||
virtual void GenerateExtensionCode(io::Printer* printer) override;
|
||||
};
|
||||
|
||||
class EnumOneofFieldGenerator : public PrimitiveOneofFieldGenerator {
|
||||
public:
|
||||
EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int presenceIndex,
|
||||
const Options *options);
|
||||
~EnumOneofFieldGenerator();
|
||||
|
||||
EnumOneofFieldGenerator(const EnumOneofFieldGenerator&) = delete;
|
||||
EnumOneofFieldGenerator& operator=(const EnumOneofFieldGenerator&) = delete;
|
||||
|
||||
virtual void GenerateMergingCode(io::Printer* printer) override;
|
||||
virtual void GenerateParsingCode(io::Printer* printer) override;
|
||||
virtual void GenerateSerializationCode(io::Printer* printer) override;
|
||||
virtual void GenerateSerializedSizeCode(io::Printer* printer) override;
|
||||
};
|
||||
|
||||
} // namespace csharp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__
|
||||
|
||||
@@ -0,0 +1,467 @@
|
||||
// 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/compiler/csharp/csharp_field_base.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
|
||||
#include "google/protobuf/compiler/code_generator.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/wire_format.h"
|
||||
#include "google/protobuf/compiler/csharp/csharp_helpers.h"
|
||||
#include "google/protobuf/compiler/csharp/names.h"
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
#include "google/protobuf/io/coded_stream.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
|
||||
// Must be last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace csharp {
|
||||
|
||||
void FieldGeneratorBase::SetCommonFieldVariables(
|
||||
std::map<std::string, std::string>* variables) {
|
||||
// Note: this will be valid even though the tag emitted for packed and unpacked versions of
|
||||
// repeated fields varies by wire format. The wire format is encoded in the bottom 3 bits, which
|
||||
// never effects the tag size.
|
||||
int tag_size = internal::WireFormat::TagSize(descriptor_->number(), descriptor_->type());
|
||||
int part_tag_size = tag_size;
|
||||
if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
|
||||
part_tag_size /= 2;
|
||||
}
|
||||
uint tag = internal::WireFormat::MakeTag(descriptor_);
|
||||
uint8_t tag_array[5];
|
||||
io::CodedOutputStream::WriteTagToArray(tag, tag_array);
|
||||
std::string tag_bytes = absl::StrCat(tag_array[0]);
|
||||
for (int i = 1; i < part_tag_size; i++) {
|
||||
tag_bytes += ", " + absl::StrCat(tag_array[i]);
|
||||
}
|
||||
|
||||
(*variables)["tag"] = absl::StrCat(tag);
|
||||
(*variables)["tag_size"] = absl::StrCat(tag_size);
|
||||
(*variables)["tag_bytes"] = tag_bytes;
|
||||
|
||||
if (descriptor_->type() == FieldDescriptor::Type::TYPE_GROUP) {
|
||||
tag = internal::WireFormatLite::MakeTag(
|
||||
descriptor_->number(),
|
||||
internal::WireFormatLite::WIRETYPE_END_GROUP);
|
||||
io::CodedOutputStream::WriteTagToArray(tag, tag_array);
|
||||
tag_bytes = absl::StrCat(tag_array[0]);
|
||||
for (int i = 1; i < part_tag_size; i++) {
|
||||
tag_bytes += ", " + absl::StrCat(tag_array[i]);
|
||||
}
|
||||
|
||||
variables_["end_tag"] = absl::StrCat(tag);
|
||||
variables_["end_tag_bytes"] = tag_bytes;
|
||||
}
|
||||
|
||||
(*variables)["access_level"] = "public";
|
||||
|
||||
(*variables)["property_name"] = property_name();
|
||||
(*variables)["type_name"] = type_name();
|
||||
(*variables)["extended_type"] = GetClassName(descriptor_->containing_type());
|
||||
(*variables)["name"] = name();
|
||||
(*variables)["descriptor_name"] = descriptor_->name();
|
||||
(*variables)["default_value"] = default_value();
|
||||
(*variables)["capitalized_type_name"] = capitalized_type_name();
|
||||
(*variables)["number"] = number();
|
||||
if (has_default_value() && !SupportsPresenceApi(descriptor_)) {
|
||||
(*variables)["name_def_message"] =
|
||||
(*variables)["name"] + "_ = " + (*variables)["default_value"];
|
||||
} else {
|
||||
(*variables)["name_def_message"] = (*variables)["name"] + "_";
|
||||
}
|
||||
if (SupportsPresenceApi(descriptor_)) {
|
||||
(*variables)["has_property_check"] = "Has" + (*variables)["property_name"];
|
||||
(*variables)["other_has_property_check"] = "other.Has" + (*variables)["property_name"];
|
||||
(*variables)["has_not_property_check"] = "!" + (*variables)["has_property_check"];
|
||||
(*variables)["other_has_not_property_check"] = "!" + (*variables)["other_has_property_check"];
|
||||
if (presenceIndex_ != -1) {
|
||||
std::string hasBitsNumber = absl::StrCat(presenceIndex_ / 32);
|
||||
std::string hasBitsMask = absl::StrCat(1 << (presenceIndex_ % 32));
|
||||
(*variables)["has_field_check"] = "(_hasBits" + hasBitsNumber + " & " + hasBitsMask + ") != 0";
|
||||
(*variables)["set_has_field"] = "_hasBits" + hasBitsNumber + " |= " + hasBitsMask;
|
||||
(*variables)["clear_has_field"] = "_hasBits" + hasBitsNumber + " &= ~" + hasBitsMask;
|
||||
}
|
||||
} else {
|
||||
(*variables)["has_property_check"] =
|
||||
(*variables)["property_name"] + " != " + (*variables)["default_value"];
|
||||
(*variables)["other_has_property_check"] = "other." +
|
||||
(*variables)["property_name"] + " != " + (*variables)["default_value"];
|
||||
}
|
||||
}
|
||||
|
||||
void FieldGeneratorBase::SetCommonOneofFieldVariables(
|
||||
std::map<std::string, std::string>* variables) {
|
||||
(*variables)["oneof_name"] = oneof_name();
|
||||
if (SupportsPresenceApi(descriptor_)) {
|
||||
(*variables)["has_property_check"] = "Has" + property_name();
|
||||
} else {
|
||||
(*variables)["has_property_check"] =
|
||||
oneof_name() + "Case_ == " + oneof_property_name() +
|
||||
"OneofCase." + oneof_case_name();
|
||||
}
|
||||
(*variables)["oneof_case_name"] = oneof_case_name();
|
||||
(*variables)["oneof_property_name"] = oneof_property_name();
|
||||
}
|
||||
|
||||
FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* descriptor,
|
||||
int presenceIndex, const Options* options)
|
||||
: SourceGeneratorBase(options),
|
||||
descriptor_(descriptor),
|
||||
presenceIndex_(presenceIndex) {
|
||||
SetCommonFieldVariables(&variables_);
|
||||
}
|
||||
|
||||
FieldGeneratorBase::~FieldGeneratorBase() {
|
||||
}
|
||||
|
||||
void FieldGeneratorBase::GenerateFreezingCode(io::Printer* printer) {
|
||||
// No-op: only message fields and repeated fields need
|
||||
// special handling for freezing, so default to not generating any code.
|
||||
}
|
||||
|
||||
void FieldGeneratorBase::GenerateCodecCode(io::Printer* printer) {
|
||||
// No-op: expect this to be overridden by appropriate types.
|
||||
// Could fail if we get called here though...
|
||||
}
|
||||
|
||||
void FieldGeneratorBase::GenerateExtensionCode(io::Printer* printer) {
|
||||
// No-op: only message fields, enum fields, primitives,
|
||||
// and repeated fields need this default is to not generate any code
|
||||
}
|
||||
|
||||
void FieldGeneratorBase::GenerateParsingCode(io::Printer* printer, bool use_parse_context) {
|
||||
// for some field types the value of "use_parse_context" doesn't matter,
|
||||
// so we fallback to the default implementation.
|
||||
GenerateParsingCode(printer);
|
||||
}
|
||||
|
||||
void FieldGeneratorBase::GenerateSerializationCode(io::Printer* printer, bool use_write_context) {
|
||||
// for some field types the value of "use_write_context" doesn't matter,
|
||||
// so we fallback to the default implementation.
|
||||
GenerateSerializationCode(printer);
|
||||
}
|
||||
|
||||
void FieldGeneratorBase::AddDeprecatedFlag(io::Printer* printer) {
|
||||
if (descriptor_->options().deprecated()) {
|
||||
printer->Print("[global::System.ObsoleteAttribute]\n");
|
||||
} else if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE &&
|
||||
descriptor_->message_type()->options().deprecated()) {
|
||||
printer->Print("[global::System.ObsoleteAttribute]\n");
|
||||
}
|
||||
}
|
||||
|
||||
void FieldGeneratorBase::AddPublicMemberAttributes(io::Printer* printer) {
|
||||
AddDeprecatedFlag(printer);
|
||||
WriteGeneratedCodeAttributes(printer);
|
||||
}
|
||||
|
||||
std::string FieldGeneratorBase::oneof_case_name() {
|
||||
return GetOneofCaseName(descriptor_);
|
||||
}
|
||||
|
||||
std::string FieldGeneratorBase::oneof_property_name() {
|
||||
return UnderscoresToCamelCase(descriptor_->containing_oneof()->name(), true);
|
||||
}
|
||||
|
||||
std::string FieldGeneratorBase::oneof_name() {
|
||||
return UnderscoresToCamelCase(descriptor_->containing_oneof()->name(), false);
|
||||
}
|
||||
|
||||
std::string FieldGeneratorBase::property_name() {
|
||||
return GetPropertyName(descriptor_);
|
||||
}
|
||||
|
||||
std::string FieldGeneratorBase::name() {
|
||||
return UnderscoresToCamelCase(GetFieldName(descriptor_), false);
|
||||
}
|
||||
|
||||
std::string FieldGeneratorBase::type_name() {
|
||||
return type_name(descriptor_);
|
||||
}
|
||||
|
||||
std::string FieldGeneratorBase::type_name(const FieldDescriptor* descriptor) {
|
||||
switch (descriptor->type()) {
|
||||
case FieldDescriptor::TYPE_ENUM:
|
||||
return GetClassName(descriptor->enum_type());
|
||||
case FieldDescriptor::TYPE_MESSAGE:
|
||||
case FieldDescriptor::TYPE_GROUP:
|
||||
if (IsWrapperType(descriptor)) {
|
||||
const FieldDescriptor* wrapped_field =
|
||||
descriptor->message_type()->field(0);
|
||||
std::string wrapped_field_type_name = type_name(wrapped_field);
|
||||
// String and ByteString go to the same type; other wrapped types
|
||||
// go to the nullable equivalent.
|
||||
if (wrapped_field->type() == FieldDescriptor::TYPE_STRING ||
|
||||
wrapped_field->type() == FieldDescriptor::TYPE_BYTES) {
|
||||
return wrapped_field_type_name;
|
||||
} else {
|
||||
return wrapped_field_type_name + "?";
|
||||
}
|
||||
}
|
||||
return GetClassName(descriptor->message_type());
|
||||
case FieldDescriptor::TYPE_DOUBLE:
|
||||
return "double";
|
||||
case FieldDescriptor::TYPE_FLOAT:
|
||||
return "float";
|
||||
case FieldDescriptor::TYPE_INT64:
|
||||
return "long";
|
||||
case FieldDescriptor::TYPE_UINT64:
|
||||
return "ulong";
|
||||
case FieldDescriptor::TYPE_INT32:
|
||||
return "int";
|
||||
case FieldDescriptor::TYPE_FIXED64:
|
||||
return "ulong";
|
||||
case FieldDescriptor::TYPE_FIXED32:
|
||||
return "uint";
|
||||
case FieldDescriptor::TYPE_BOOL:
|
||||
return "bool";
|
||||
case FieldDescriptor::TYPE_STRING:
|
||||
return "string";
|
||||
case FieldDescriptor::TYPE_BYTES:
|
||||
return "pb::ByteString";
|
||||
case FieldDescriptor::TYPE_UINT32:
|
||||
return "uint";
|
||||
case FieldDescriptor::TYPE_SFIXED32:
|
||||
return "int";
|
||||
case FieldDescriptor::TYPE_SFIXED64:
|
||||
return "long";
|
||||
case FieldDescriptor::TYPE_SINT32:
|
||||
return "int";
|
||||
case FieldDescriptor::TYPE_SINT64:
|
||||
return "long";
|
||||
default:
|
||||
GOOGLE_LOG(FATAL)<< "Unknown field type.";
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
bool FieldGeneratorBase::has_default_value() {
|
||||
switch (descriptor_->type()) {
|
||||
case FieldDescriptor::TYPE_ENUM:
|
||||
case FieldDescriptor::TYPE_MESSAGE:
|
||||
case FieldDescriptor::TYPE_GROUP:
|
||||
return true;
|
||||
case FieldDescriptor::TYPE_DOUBLE:
|
||||
return descriptor_->default_value_double() != 0.0;
|
||||
case FieldDescriptor::TYPE_FLOAT:
|
||||
return descriptor_->default_value_float() != 0.0;
|
||||
case FieldDescriptor::TYPE_INT64:
|
||||
return descriptor_->default_value_int64() != 0L;
|
||||
case FieldDescriptor::TYPE_UINT64:
|
||||
return descriptor_->default_value_uint64() != 0L;
|
||||
case FieldDescriptor::TYPE_INT32:
|
||||
return descriptor_->default_value_int32() != 0;
|
||||
case FieldDescriptor::TYPE_FIXED64:
|
||||
return descriptor_->default_value_uint64() != 0L;
|
||||
case FieldDescriptor::TYPE_FIXED32:
|
||||
return descriptor_->default_value_uint32() != 0;
|
||||
case FieldDescriptor::TYPE_BOOL:
|
||||
return descriptor_->default_value_bool();
|
||||
case FieldDescriptor::TYPE_STRING:
|
||||
return true;
|
||||
case FieldDescriptor::TYPE_BYTES:
|
||||
return true;
|
||||
case FieldDescriptor::TYPE_UINT32:
|
||||
return descriptor_->default_value_uint32() != 0;
|
||||
case FieldDescriptor::TYPE_SFIXED32:
|
||||
return descriptor_->default_value_int32() != 0;
|
||||
case FieldDescriptor::TYPE_SFIXED64:
|
||||
return descriptor_->default_value_int64() != 0L;
|
||||
case FieldDescriptor::TYPE_SINT32:
|
||||
return descriptor_->default_value_int32() != 0;
|
||||
case FieldDescriptor::TYPE_SINT64:
|
||||
return descriptor_->default_value_int64() != 0L;
|
||||
default:
|
||||
GOOGLE_LOG(FATAL)<< "Unknown field type.";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool AllPrintableAscii(const std::string& text) {
|
||||
for(int i = 0; i < text.size(); i++) {
|
||||
if (text[i] < 0x20 || text[i] > 0x7e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string FieldGeneratorBase::GetStringDefaultValueInternal(const FieldDescriptor* descriptor) {
|
||||
if (descriptor->default_value_string().empty())
|
||||
return "\"\"";
|
||||
else
|
||||
return "global::System.Text.Encoding.UTF8.GetString(global::System."
|
||||
"Convert.FromBase64String(\"" +
|
||||
StringToBase64(descriptor->default_value_string()) + "\"), 0, " + absl::StrCat(descriptor->default_value_string().length()) + ")";
|
||||
}
|
||||
|
||||
std::string FieldGeneratorBase::GetBytesDefaultValueInternal(const FieldDescriptor* descriptor) {
|
||||
if (descriptor->default_value_string().empty())
|
||||
return "pb::ByteString.Empty";
|
||||
else
|
||||
return "pb::ByteString.FromBase64(\"" + StringToBase64(descriptor->default_value_string()) + "\")";
|
||||
}
|
||||
|
||||
std::string FieldGeneratorBase::default_value() {
|
||||
return default_value(descriptor_);
|
||||
}
|
||||
|
||||
std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor) {
|
||||
switch (descriptor->type()) {
|
||||
case FieldDescriptor::TYPE_ENUM:
|
||||
return GetClassName(descriptor->default_value_enum()->type()) + "." +
|
||||
GetEnumValueName(descriptor->default_value_enum()->type()->name(), descriptor->default_value_enum()->name());
|
||||
case FieldDescriptor::TYPE_MESSAGE:
|
||||
case FieldDescriptor::TYPE_GROUP:
|
||||
if (IsWrapperType(descriptor)) {
|
||||
const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
|
||||
return default_value(wrapped_field);
|
||||
} else {
|
||||
return "null";
|
||||
}
|
||||
case FieldDescriptor::TYPE_DOUBLE: {
|
||||
double value = descriptor->default_value_double();
|
||||
if (value == std::numeric_limits<double>::infinity()) {
|
||||
return "double.PositiveInfinity";
|
||||
} else if (value == -std::numeric_limits<double>::infinity()) {
|
||||
return "double.NegativeInfinity";
|
||||
} else if (std::isnan(value)) {
|
||||
return "double.NaN";
|
||||
}
|
||||
return absl::StrCat(value) + "D";
|
||||
}
|
||||
case FieldDescriptor::TYPE_FLOAT: {
|
||||
float value = descriptor->default_value_float();
|
||||
if (value == std::numeric_limits<float>::infinity()) {
|
||||
return "float.PositiveInfinity";
|
||||
} else if (value == -std::numeric_limits<float>::infinity()) {
|
||||
return "float.NegativeInfinity";
|
||||
} else if (std::isnan(value)) {
|
||||
return "float.NaN";
|
||||
}
|
||||
return absl::StrCat(value) + "F";
|
||||
}
|
||||
case FieldDescriptor::TYPE_INT64:
|
||||
return absl::StrCat(descriptor->default_value_int64()) + "L";
|
||||
case FieldDescriptor::TYPE_UINT64:
|
||||
return absl::StrCat(descriptor->default_value_uint64()) + "UL";
|
||||
case FieldDescriptor::TYPE_INT32:
|
||||
return absl::StrCat(descriptor->default_value_int32());
|
||||
case FieldDescriptor::TYPE_FIXED64:
|
||||
return absl::StrCat(descriptor->default_value_uint64()) + "UL";
|
||||
case FieldDescriptor::TYPE_FIXED32:
|
||||
return absl::StrCat(descriptor->default_value_uint32());
|
||||
case FieldDescriptor::TYPE_BOOL:
|
||||
if (descriptor->default_value_bool()) {
|
||||
return "true";
|
||||
} else {
|
||||
return "false";
|
||||
}
|
||||
case FieldDescriptor::TYPE_STRING:
|
||||
return GetStringDefaultValueInternal(descriptor);
|
||||
case FieldDescriptor::TYPE_BYTES:
|
||||
return GetBytesDefaultValueInternal(descriptor);
|
||||
case FieldDescriptor::TYPE_UINT32:
|
||||
return absl::StrCat(descriptor->default_value_uint32());
|
||||
case FieldDescriptor::TYPE_SFIXED32:
|
||||
return absl::StrCat(descriptor->default_value_int32());
|
||||
case FieldDescriptor::TYPE_SFIXED64:
|
||||
return absl::StrCat(descriptor->default_value_int64()) + "L";
|
||||
case FieldDescriptor::TYPE_SINT32:
|
||||
return absl::StrCat(descriptor->default_value_int32());
|
||||
case FieldDescriptor::TYPE_SINT64:
|
||||
return absl::StrCat(descriptor->default_value_int64()) + "L";
|
||||
default:
|
||||
GOOGLE_LOG(FATAL)<< "Unknown field type.";
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
std::string FieldGeneratorBase::number() {
|
||||
return absl::StrCat(descriptor_->number());
|
||||
}
|
||||
|
||||
std::string FieldGeneratorBase::capitalized_type_name() {
|
||||
switch (descriptor_->type()) {
|
||||
case FieldDescriptor::TYPE_ENUM:
|
||||
return "Enum";
|
||||
case FieldDescriptor::TYPE_MESSAGE:
|
||||
return "Message";
|
||||
case FieldDescriptor::TYPE_GROUP:
|
||||
return "Group";
|
||||
case FieldDescriptor::TYPE_DOUBLE:
|
||||
return "Double";
|
||||
case FieldDescriptor::TYPE_FLOAT:
|
||||
return "Float";
|
||||
case FieldDescriptor::TYPE_INT64:
|
||||
return "Int64";
|
||||
case FieldDescriptor::TYPE_UINT64:
|
||||
return "UInt64";
|
||||
case FieldDescriptor::TYPE_INT32:
|
||||
return "Int32";
|
||||
case FieldDescriptor::TYPE_FIXED64:
|
||||
return "Fixed64";
|
||||
case FieldDescriptor::TYPE_FIXED32:
|
||||
return "Fixed32";
|
||||
case FieldDescriptor::TYPE_BOOL:
|
||||
return "Bool";
|
||||
case FieldDescriptor::TYPE_STRING:
|
||||
return "String";
|
||||
case FieldDescriptor::TYPE_BYTES:
|
||||
return "Bytes";
|
||||
case FieldDescriptor::TYPE_UINT32:
|
||||
return "UInt32";
|
||||
case FieldDescriptor::TYPE_SFIXED32:
|
||||
return "SFixed32";
|
||||
case FieldDescriptor::TYPE_SFIXED64:
|
||||
return "SFixed64";
|
||||
case FieldDescriptor::TYPE_SINT32:
|
||||
return "SInt32";
|
||||
case FieldDescriptor::TYPE_SINT64:
|
||||
return "SInt64";
|
||||
default:
|
||||
GOOGLE_LOG(FATAL)<< "Unknown field type.";
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace csharp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
@@ -0,0 +1,116 @@
|
||||
// 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.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "google/protobuf/compiler/code_generator.h"
|
||||
#include "google/protobuf/stubs/strutil.h"
|
||||
#include "absl/strings/ascii.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/strings/str_replace.h"
|
||||
#include "absl/strings/str_split.h"
|
||||
#include "google/protobuf/compiler/csharp/csharp_source_generator_base.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace csharp {
|
||||
|
||||
class FieldGeneratorBase : public SourceGeneratorBase {
|
||||
public:
|
||||
FieldGeneratorBase(const FieldDescriptor* descriptor,
|
||||
int presenceIndex,
|
||||
const Options* options);
|
||||
~FieldGeneratorBase();
|
||||
|
||||
FieldGeneratorBase(const FieldGeneratorBase&) = delete;
|
||||
FieldGeneratorBase& operator=(const FieldGeneratorBase&) = delete;
|
||||
|
||||
virtual void GenerateCloningCode(io::Printer* printer) = 0;
|
||||
virtual void GenerateFreezingCode(io::Printer* printer);
|
||||
virtual void GenerateCodecCode(io::Printer* printer);
|
||||
virtual void GenerateExtensionCode(io::Printer* printer);
|
||||
virtual void GenerateMembers(io::Printer* printer) = 0;
|
||||
virtual void GenerateMergingCode(io::Printer* printer) = 0;
|
||||
virtual void GenerateParsingCode(io::Printer* printer) = 0;
|
||||
virtual void GenerateParsingCode(io::Printer* printer, bool use_parse_context);
|
||||
virtual void GenerateSerializationCode(io::Printer* printer) = 0;
|
||||
virtual void GenerateSerializationCode(io::Printer* printer, bool use_write_context);
|
||||
virtual void GenerateSerializedSizeCode(io::Printer* printer) = 0;
|
||||
|
||||
virtual void WriteHash(io::Printer* printer) = 0;
|
||||
virtual void WriteEquals(io::Printer* printer) = 0;
|
||||
// Currently unused, as we use reflection to generate JSON
|
||||
virtual void WriteToString(io::Printer* printer) = 0;
|
||||
|
||||
protected:
|
||||
const FieldDescriptor* descriptor_;
|
||||
const int presenceIndex_;
|
||||
std::map<std::string, std::string> variables_;
|
||||
|
||||
void AddDeprecatedFlag(io::Printer* printer);
|
||||
void AddNullCheck(io::Printer* printer);
|
||||
void AddNullCheck(io::Printer* printer, const std::string& name);
|
||||
|
||||
void AddPublicMemberAttributes(io::Printer* printer);
|
||||
void SetCommonOneofFieldVariables(
|
||||
std::map<std::string, std::string>* variables);
|
||||
|
||||
std::string oneof_property_name();
|
||||
std::string oneof_case_name();
|
||||
std::string oneof_name();
|
||||
std::string property_name();
|
||||
std::string name();
|
||||
std::string type_name();
|
||||
std::string type_name(const FieldDescriptor* descriptor);
|
||||
bool has_default_value();
|
||||
std::string default_value();
|
||||
std::string default_value(const FieldDescriptor* descriptor);
|
||||
std::string number();
|
||||
std::string capitalized_type_name();
|
||||
|
||||
private:
|
||||
void SetCommonFieldVariables(std::map<std::string, std::string>* variables);
|
||||
std::string GetStringDefaultValueInternal(const FieldDescriptor* descriptor);
|
||||
std::string GetBytesDefaultValueInternal(const FieldDescriptor* descriptor);
|
||||
};
|
||||
|
||||
} // namespace csharp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
// 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/compiler/csharp/csharp_generator.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "google/protobuf/compiler/code_generator.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/compiler/csharp/csharp_helpers.h"
|
||||
#include "google/protobuf/compiler/csharp/csharp_options.h"
|
||||
#include "google/protobuf/compiler/csharp/csharp_reflection_class.h"
|
||||
#include "google/protobuf/compiler/csharp/names.h"
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "google/protobuf/io/zero_copy_stream.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace csharp {
|
||||
|
||||
Generator::Generator() {}
|
||||
Generator::~Generator() {}
|
||||
|
||||
uint64_t Generator::GetSupportedFeatures() const {
|
||||
return CodeGenerator::Feature::FEATURE_PROTO3_OPTIONAL;
|
||||
}
|
||||
|
||||
void GenerateFile(const FileDescriptor* file, io::Printer* printer,
|
||||
const Options* options) {
|
||||
ReflectionClassGenerator reflectionClassGenerator(file, options);
|
||||
reflectionClassGenerator.Generate(printer);
|
||||
}
|
||||
|
||||
bool Generator::Generate(const FileDescriptor* file,
|
||||
const std::string& parameter,
|
||||
GeneratorContext* generator_context,
|
||||
std::string* error) const {
|
||||
std::vector<std::pair<std::string, std::string> > options;
|
||||
ParseGeneratorParameter(parameter, &options);
|
||||
|
||||
struct Options cli_options;
|
||||
|
||||
for (int i = 0; i < options.size(); i++) {
|
||||
if (options[i].first == "file_extension") {
|
||||
cli_options.file_extension = options[i].second;
|
||||
} else if (options[i].first == "base_namespace") {
|
||||
cli_options.base_namespace = options[i].second;
|
||||
cli_options.base_namespace_specified = true;
|
||||
} else if (options[i].first == "internal_access") {
|
||||
cli_options.internal_access = true;
|
||||
} else if (options[i].first == "serializable") {
|
||||
cli_options.serializable = true;
|
||||
} else {
|
||||
*error = "Unknown generator option: " + options[i].first;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string filename_error = "";
|
||||
std::string filename = GetOutputFile(file,
|
||||
cli_options.file_extension,
|
||||
cli_options.base_namespace_specified,
|
||||
cli_options.base_namespace,
|
||||
&filename_error);
|
||||
|
||||
if (filename.empty()) {
|
||||
*error = filename_error;
|
||||
return false;
|
||||
}
|
||||
std::unique_ptr<io::ZeroCopyOutputStream> output(
|
||||
generator_context->Open(filename));
|
||||
io::Printer printer(output.get(), '$');
|
||||
|
||||
GenerateFile(file, &printer, &cli_options);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace csharp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
@@ -0,0 +1,70 @@
|
||||
// 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.
|
||||
|
||||
// Generates C# code for a given .proto file.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "google/protobuf/compiler/code_generator.h"
|
||||
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace csharp {
|
||||
|
||||
// CodeGenerator implementation which generates a C# source file and
|
||||
// header. If you create your own protocol compiler binary and you want
|
||||
// it to support C# output, you can do so by registering an instance of this
|
||||
// CodeGenerator with the CommandLineInterface in your main() function.
|
||||
class PROTOC_EXPORT Generator : public CodeGenerator {
|
||||
public:
|
||||
Generator();
|
||||
~Generator();
|
||||
bool Generate(
|
||||
const FileDescriptor* file,
|
||||
const std::string& parameter,
|
||||
GeneratorContext* generator_context,
|
||||
std::string* error) const override;
|
||||
uint64_t GetSupportedFeatures() const override;
|
||||
};
|
||||
|
||||
} // namespace csharp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__
|
||||
@@ -0,0 +1,96 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2014 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 <memory>
|
||||
|
||||
#include "google/protobuf/any.pb.h"
|
||||
#include "google/protobuf/compiler/command_line_interface.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include "google/protobuf/compiler/csharp/csharp_helpers.h"
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "google/protobuf/io/zero_copy_stream.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace csharp {
|
||||
namespace {
|
||||
|
||||
TEST(CSharpEnumValue, PascalCasedPrefixStripping) {
|
||||
EXPECT_EQ("Bar", GetEnumValueName("Foo", "BAR"));
|
||||
EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "BAR_BAZ"));
|
||||
EXPECT_EQ("Bar", GetEnumValueName("Foo", "FOO_BAR"));
|
||||
EXPECT_EQ("Bar", GetEnumValueName("Foo", "FOO__BAR"));
|
||||
EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "FOO_BAR_BAZ"));
|
||||
EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "Foo_BarBaz"));
|
||||
EXPECT_EQ("Bar", GetEnumValueName("FO_O", "FOO_BAR"));
|
||||
EXPECT_EQ("Bar", GetEnumValueName("FOO", "F_O_O_BAR"));
|
||||
EXPECT_EQ("Bar", GetEnumValueName("Foo", "BAR"));
|
||||
EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "BAR_BAZ"));
|
||||
EXPECT_EQ("Foo", GetEnumValueName("Foo", "FOO"));
|
||||
EXPECT_EQ("Foo", GetEnumValueName("Foo", "FOO___"));
|
||||
// Identifiers can't start with digits
|
||||
EXPECT_EQ("_2Bar", GetEnumValueName("Foo", "FOO_2_BAR"));
|
||||
EXPECT_EQ("_2", GetEnumValueName("Foo", "FOO___2"));
|
||||
}
|
||||
|
||||
TEST(DescriptorProtoHelpers, IsDescriptorProto) {
|
||||
EXPECT_TRUE(IsDescriptorProto(DescriptorProto::descriptor()->file()));
|
||||
EXPECT_FALSE(IsDescriptorProto(google::protobuf::Any::descriptor()->file()));
|
||||
}
|
||||
|
||||
TEST(DescriptorProtoHelpers, IsDescriptorOptionMessage) {
|
||||
EXPECT_TRUE(IsDescriptorOptionMessage(FileOptions::descriptor()));
|
||||
EXPECT_FALSE(IsDescriptorOptionMessage(google::protobuf::Any::descriptor()));
|
||||
EXPECT_FALSE(IsDescriptorOptionMessage(DescriptorProto::descriptor()));
|
||||
}
|
||||
|
||||
TEST(CSharpIdentifiers, UnderscoresToCamelCase) {
|
||||
EXPECT_EQ("FooBar", UnderscoresToCamelCase("Foo_Bar", true));
|
||||
EXPECT_EQ("fooBar", UnderscoresToCamelCase("FooBar", false));
|
||||
EXPECT_EQ("foo123", UnderscoresToCamelCase("foo_123", false));
|
||||
// remove leading underscores
|
||||
EXPECT_EQ("Foo123", UnderscoresToCamelCase("_Foo_123", true));
|
||||
// this one has slight unexpected output as it capitalises the first
|
||||
// letter after consuming the underscores, but this was the existing
|
||||
// behaviour so I have not changed it
|
||||
EXPECT_EQ("FooBar", UnderscoresToCamelCase("___fooBar", false));
|
||||
// leave a leading underscore for identifiers that would otherwise
|
||||
// be invalid because they would start with a digit
|
||||
EXPECT_EQ("_123Foo", UnderscoresToCamelCase("_123_foo", true));
|
||||
EXPECT_EQ("_123Foo", UnderscoresToCamelCase("___123_foo", true));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace csharp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user