mirror of
https://github.com/protocolbuffers/protobuf
synced 2026-08-26 02:23:14 -04:00
Merge branch 'main' into protowire-options-range
This commit is contained in:
commit
a3d24a95ff
118 changed files with 4000 additions and 1890 deletions
2
.github/workflows/test_bazel.yml
vendored
2
.github/workflows/test_bazel.yml
vendored
|
|
@ -94,7 +94,7 @@ jobs:
|
|||
- name: Run tests
|
||||
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
|
||||
with:
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.0.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.2.0-4d8e80ef93b0219fb907af9dd4596b92946995d8
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
bazel-cache: "bazel-tests"
|
||||
bazel: test //bazel/...
|
||||
|
|
|
|||
39
.github/workflows/test_cpp.yml
vendored
39
.github/workflows/test_cpp.yml
vendored
|
|
@ -37,25 +37,25 @@ jobs:
|
|||
- { name: No-RTTI, flags: --cxxopt=-fno-rtti, continuous-only: true }
|
||||
include:
|
||||
# Set defaults
|
||||
- image: us-docker.pkg.dev/protobuf-build/containers/test/linux/sanitize:8.0.1-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
|
||||
- image: us-docker.pkg.dev/protobuf-build/containers/test/linux/sanitize:8.7.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
|
||||
- targets: //pkg/... //src/... //third_party/utf8_range/... //conformance:conformance_framework_tests
|
||||
# Override cases with custom images
|
||||
- config: { name: "Bazel8", flags: --cxxopt="-Wno-self-assign-overloaded" }
|
||||
cache_key: Bazel8
|
||||
image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:8.6.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c"
|
||||
image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:8.7.0-4d8e80ef93b0219fb907af9dd4596b92946995d8"
|
||||
targets: "//src/... //third_party/utf8_range/..."
|
||||
- config: { name: "Bazel9", flags: "--cxxopt=-Wno-self-assign-overloaded" }
|
||||
cache_key: Bazel9
|
||||
image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.0.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c"
|
||||
image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.2.0-4d8e80ef93b0219fb907af9dd4596b92946995d8"
|
||||
targets: "//src/... //third_party/utf8_range/..."
|
||||
- config: { name: "TCMalloc" }
|
||||
cache_key: TcMalloc
|
||||
image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/tcmalloc:8.0.1-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12"
|
||||
image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/tcmalloc:8.7.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 "
|
||||
targets: "//src/... //third_party/utf8_range/..."
|
||||
- config: { name: "aarch64", flags: "--platforms=//build_defs:linux-aarch_64" }
|
||||
cache_key: aarch64-bazel8
|
||||
targets: "//src/... //src/google/protobuf/compiler:protoc_aarch64_test //third_party/utf8_range/..."
|
||||
image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:8.0.1-aarch64-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12"
|
||||
image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:8.7.0-aarch64-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 "
|
||||
name: ${{ matrix.config.continuous-only && inputs.continuous-prefix || '' }} Linux ${{ matrix.config.name }}
|
||||
runs-on: ${{ matrix.config.runner || 'ubuntu-latest' }}
|
||||
steps:
|
||||
|
|
@ -64,6 +64,15 @@ jobs:
|
|||
uses: protocolbuffers/protobuf-ci/checkout@v5
|
||||
with:
|
||||
ref: ${{ inputs.safe-checkout }}
|
||||
- name: Prime the cache
|
||||
if: ${{ !matrix.config.continuous-only || inputs.continuous-run }}
|
||||
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
|
||||
with:
|
||||
image: ${{ matrix.image }}
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
bazel-cache: cpp_linux/${{ matrix.cache_key }}
|
||||
bazel: fetch ${{ matrix.targets }} ${{ matrix.config.flags }}
|
||||
exclude-targets: ${{ matrix.exclude-targets }}
|
||||
- name: Run tests
|
||||
if: ${{ !matrix.config.continuous-only || inputs.continuous-run }}
|
||||
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
|
||||
|
|
@ -78,7 +87,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false # Don't cancel all jobs if one fails.
|
||||
matrix:
|
||||
version: ['10.4', '13.1']
|
||||
version: ['10.5', '13.4']
|
||||
name: ${{ matrix.config.continuous-only && inputs.continuous-prefix || '' }} Linux GCC ${{ matrix.version }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
|
@ -87,11 +96,19 @@ jobs:
|
|||
if: ${{ !matrix.config.continuous-only || inputs.continuous-run }}
|
||||
with:
|
||||
ref: ${{ inputs.safe-checkout }}
|
||||
- name: Prime the cache
|
||||
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
|
||||
if: ${{ !matrix.config.continuous-only || inputs.continuous-run }}
|
||||
with:
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.7.0-${{ matrix.version }}-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
bazel-cache: cpp_linux/gcc-${{ matrix.version }}
|
||||
bazel: fetch //pkg/... //src/... //third_party/utf8_range/... //conformance:conformance_framework_tests
|
||||
- name: Run tests
|
||||
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
|
||||
if: ${{ !matrix.config.continuous-only || inputs.continuous-run }}
|
||||
with:
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.0.1-${{ matrix.version }}-e78301df86b3e4c46ec9ac4d98be00e19305d8f3
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.7.0-${{ matrix.version }}-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
bazel-cache: cpp_linux/gcc-${{ matrix.version }}
|
||||
bazel: test //pkg/... //src/... //third_party/utf8_range/... //conformance:conformance_framework_tests
|
||||
|
|
@ -125,7 +142,7 @@ jobs:
|
|||
id: cross-compile
|
||||
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v5
|
||||
with:
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:8.6.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:8.7.0-4d8e80ef93b0219fb907af9dd4596b92946995d8
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
architecture: linux-${{ matrix.arch }}
|
||||
- name: Check disk space after cross compile
|
||||
|
|
@ -146,7 +163,7 @@ jobs:
|
|||
if: ${{ !matrix.continuous-only || inputs.continuous-run }}
|
||||
uses: protocolbuffers/protobuf-ci/docker@v5
|
||||
with:
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:8.0.1-${{ matrix.arch }}-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:8.7.0-${{ matrix.arch }}-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
entrypoint: bash
|
||||
command: >
|
||||
|
|
@ -386,7 +403,7 @@ jobs:
|
|||
if: ${{ !matrix.continuous-only || inputs.continuous-run }}
|
||||
uses: protocolbuffers/protobuf-ci/docker@v5
|
||||
with:
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.0.1-12.2-168f9c9d015a0fa16611e1e9eede796fe9bfbb69
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.7.0-12.5-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
entrypoint: bash
|
||||
command: >-
|
||||
|
|
@ -608,7 +625,7 @@ jobs:
|
|||
if: ${{ inputs.continuous-run }}
|
||||
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
|
||||
with:
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.0.0-7932bf8b25fb76a111e7257d151a6a58d5c3c671
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.2.0-4d8e80ef93b0219fb907af9dd4596b92946995d8
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
bazel-cache: cpp_linux/abseil_head
|
||||
bazel: test //src/... --override_module=abseil-cpp=abseil-cpp-head
|
||||
|
|
|
|||
4
.github/workflows/test_csharp.yml
vendored
4
.github/workflows/test_csharp.yml
vendored
|
|
@ -27,7 +27,7 @@ jobs:
|
|||
- name: Run tests
|
||||
uses: protocolbuffers/protobuf-ci/docker@v5
|
||||
with:
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/csharp:9.0.0-3.1.415-8.0.100-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/csharp:9.2.0-3.1.415-8.0.100-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
entrypoint: /bin/bash
|
||||
command: >-
|
||||
|
|
@ -43,7 +43,7 @@ jobs:
|
|||
- name: Run conformance tests
|
||||
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
|
||||
with:
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/csharp:9.0.0-3.1.415-8.0.100-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/csharp:9.2.0-3.1.415-8.0.100-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
bazel-cache: csharp_linux
|
||||
bazel: test //csharp:conformance_test --action_env=PATH --action_env=DOTNET_CLI_TELEMETRY_OPTOUT=1 --test_env=DOTNET_CLI_HOME=/home/bazel
|
||||
|
|
|
|||
2
.github/workflows/test_hpb.yml
vendored
2
.github/workflows/test_hpb.yml
vendored
|
|
@ -22,7 +22,7 @@ jobs:
|
|||
|
||||
include:
|
||||
- targets: "//hpb/... //hpb_generator/..."
|
||||
- image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.0.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c"
|
||||
- image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.2.0-4d8e80ef93b0219fb907af9dd4596b92946995d8"
|
||||
- bazel_cmd: "test"
|
||||
|
||||
name: Linux ${{ matrix.config.name }}
|
||||
|
|
|
|||
12
.github/workflows/test_java.yml
vendored
12
.github/workflows/test_java.yml
vendored
|
|
@ -30,27 +30,27 @@ jobs:
|
|||
include:
|
||||
- name: OpenJDK 8
|
||||
cache_key: '8'
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.0.0-11-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.2.0-11-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
|
||||
# TODO: b/318555165 - enable the layering check. Currently it does
|
||||
# not work correctly with the toolchain in this Docker image.
|
||||
targets: //java/... //java/internal:java_version --features=-layering_check
|
||||
flags: --java_language_version=8
|
||||
- name: OpenJDK 11
|
||||
cache_key: '11'
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.0.0-11-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.2.0-11-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
|
||||
targets: //java/... //java/internal:java_version //compatibility/...
|
||||
continuous-only: true
|
||||
- name: OpenJDK 17
|
||||
cache_key: '17'
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.0.0-17-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.2.0-17-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
|
||||
targets: //java/... //java/internal:java_version //compatibility/...
|
||||
- name: OpenJDK 21 bazel 8
|
||||
cache_key: 'bazel8'
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:8.6.0-21-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:8.7.0-21-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
|
||||
targets: //java/... //java/internal:java_version //compatibility/...
|
||||
- name: OpenJDK 21
|
||||
cache_key: '21'
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.0.0-21-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.2.0-21-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
|
||||
targets: //java/... //java/internal:java_version //compatibility/...
|
||||
# TODO: b/395623141 - restore this test once runtime uses / emulates aarch64.
|
||||
# - name: aarch64
|
||||
|
|
@ -105,7 +105,7 @@ jobs:
|
|||
- name: Generate maven artifacts with bazel and install using maven
|
||||
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
|
||||
with:
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.0.0-11-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/java:9.2.0-11-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
bazel-cache: java_linux/11
|
||||
bash: |
|
||||
|
|
|
|||
6
.github/workflows/test_php.yml
vendored
6
.github/workflows/test_php.yml
vendored
|
|
@ -65,7 +65,7 @@ jobs:
|
|||
if: ${{ !matrix.continuous-only || inputs.continuous-run }}
|
||||
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
|
||||
with:
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/php:9.0.0-${{ matrix.version }}-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/php:9.2.0-${{ matrix.version }}-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
bazel-cache: php_linux/${{ matrix.version }}
|
||||
bash: |
|
||||
|
|
@ -115,7 +115,7 @@ jobs:
|
|||
id: cross-compile
|
||||
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v5
|
||||
with:
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.0.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.2.0-4d8e80ef93b0219fb907af9dd4596b92946995d8
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
architecture: linux-i386
|
||||
|
||||
|
|
@ -147,7 +147,7 @@ jobs:
|
|||
id: cross-compile
|
||||
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v5
|
||||
with:
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.0.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.2.0-4d8e80ef93b0219fb907af9dd4596b92946995d8
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
architecture: linux-aarch64
|
||||
|
||||
|
|
|
|||
4
.github/workflows/test_python.yml
vendored
4
.github/workflows/test_python.yml
vendored
|
|
@ -50,7 +50,7 @@ jobs:
|
|||
targets: //python/... //python:aarch64_test
|
||||
# TODO Enable this once conformance tests are fixed.
|
||||
flags: --define=use_fast_cpp_protos=true --test_tag_filters=-conformance
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:8.0.1-aarch64-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:8.7.0-aarch64-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7
|
||||
|
||||
name: ${{ matrix.continuous-only && inputs.continuous-prefix || '' }} Linux ${{ matrix.type }} ${{ matrix.version }} ${{ matrix.nobzlmod && 'No Bzlmod' || '' }}
|
||||
runs-on: ubuntu-latest
|
||||
|
|
@ -64,7 +64,7 @@ jobs:
|
|||
if: ${{ !matrix.continuous-only || inputs.continuous-run }}
|
||||
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
|
||||
with:
|
||||
image: ${{ matrix.image || format('us-docker.pkg.dev/protobuf-build/containers/test/linux/python:9.0.0-{0}-7932bf8b25fb76a111e7257d151a6a58d5c3c671', matrix.version) }}
|
||||
image: ${{ matrix.image || format('us-docker.pkg.dev/protobuf-build/containers/test/linux/python:9.2.0-{0}-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ', matrix.version) }}
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
bazel-cache: python_linux/${{ matrix.type }}_${{ matrix.version }}
|
||||
bazel: test ${{ matrix.targets }} ${{ matrix.flags }} ${{ matrix.nobzlmod && '--noenable_bzlmod' || '' }} --test_env=KOKORO_PYTHON_VERSION
|
||||
|
|
|
|||
24
.github/workflows/test_ruby.yml
vendored
24
.github/workflows/test_ruby.yml
vendored
|
|
@ -36,12 +36,12 @@ jobs:
|
|||
- { name: Ruby 3.4, ruby: ruby-3.4.1, continuous-only: true }
|
||||
- { name: Ruby 4.0, ruby: ruby-4.0.0, ffi: NATIVE }
|
||||
- { name: Ruby 4.0, ruby: ruby-4.0.0, ffi: FFI }
|
||||
- { name: Ruby 4.0 bazel 8, ruby: ruby-4.0.0, ffi: NATIVE, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.6.0-ruby-4.0.0-856ad422dddd3b8fbd85e36129496b37bba174ef' }
|
||||
- { name: Ruby 4.0 bazel 8, ruby: ruby-4.4.4, ffi: FFI, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.6.0-ruby-4.0.0-856ad422dddd3b8fbd85e36129496b37bba174ef' }
|
||||
- { name: Ruby 4.0 bazel 8, ruby: ruby-4.0.0, ffi: NATIVE, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.7.0-ruby-4.0.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }
|
||||
- { name: Ruby 4.0 bazel 8, ruby: ruby-4.4.4, ffi: FFI, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.7.0-ruby-4.0.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }
|
||||
- { name: JRuby 9.4, ruby: jruby-9.4.9.0, ffi: NATIVE }
|
||||
- { name: JRuby 9.4, ruby: jruby-9.4.9.0, ffi: FFI }
|
||||
- { name: JRuby 9.4 bazel 8, ruby: jruby-9.4.9.0, ffi: NATIVE, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.6.0-jruby-9.4.9.0-856ad422dddd3b8fbd85e36129496b37bba174ef' }
|
||||
- { name: JRuby 9.4 bazel 8, ruby: jruby-9.4.9.0, ffi: FFI, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.6.0-jruby-9.4.9.0-856ad422dddd3b8fbd85e36129496b37bba174ef' }
|
||||
- { name: JRuby 9.4 bazel 8, ruby: jruby-9.4.9.0, ffi: NATIVE, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.7.0-jruby-9.4.9.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }
|
||||
- { name: JRuby 9.4 bazel 8, ruby: jruby-9.4.9.0, ffi: FFI, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.7.0-jruby-9.4.9.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }
|
||||
|
||||
name: ${{ matrix.continuous-only && inputs.continuous-prefix || '' }} Linux ${{ matrix.name }} ${{ matrix.ffi == 'FFI' && ' FFI' || '' }}
|
||||
runs-on: ubuntu-latest
|
||||
|
|
@ -55,7 +55,7 @@ jobs:
|
|||
if: ${{ !matrix.continuous-only || inputs.continuous-run }}
|
||||
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
|
||||
with:
|
||||
image: ${{ matrix.image || format('us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:9.0.0-{0}-9fc33a0c378b5affd3c85d3f5ae4f330993048f7', matrix.ruby) }}
|
||||
image: ${{ matrix.image || format('us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:9.2.0-{0}-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ', matrix.ruby) }}
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
bazel-cache: ruby_linux/${{ matrix.ruby }}
|
||||
bazel: test //ruby/... //ruby/tests:ruby_version --test_env=KOKORO_RUBY_VERSION --test_env=BAZEL=true ${{ matrix.ffi == 'FFI' && '--//ruby:ffi=enabled --test_env=PROTOCOL_BUFFERS_RUBY_IMPLEMENTATION=FFI' || '' }}
|
||||
|
|
@ -81,7 +81,7 @@ jobs:
|
|||
id: cross-compile
|
||||
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v5
|
||||
with:
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:8.6.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:8.7.0-4d8e80ef93b0219fb907af9dd4596b92946995d8
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
architecture: linux-i386
|
||||
|
||||
|
|
@ -114,7 +114,7 @@ jobs:
|
|||
id: cross-compile
|
||||
uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v5
|
||||
with:
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:8.6.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c
|
||||
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:8.7.0-4d8e80ef93b0219fb907af9dd4596b92946995d8
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
architecture: linux-aarch64
|
||||
|
||||
|
|
@ -192,12 +192,12 @@ jobs:
|
|||
- { name: Ruby 3.4, ruby: ruby-3.4.1, continuous-only: true }
|
||||
- { name: Ruby 4.0, ruby: ruby-4.0.0, ffi: NATIVE }
|
||||
- { name: Ruby 4.0, ruby: ruby-4.0.0, ffi: FFI }
|
||||
- { name: Ruby 4.0 bazel 8, ruby: ruby-4.0.0, ffi: NATIVE, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.6.0-ruby-4.0.0-856ad422dddd3b8fbd85e36129496b37bba174ef' }
|
||||
- { name: Ruby 4.0 bazel 8, ruby: ruby-4.4.4, ffi: FFI, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.6.0-ruby-4.0.0-856ad422dddd3b8fbd85e36129496b37bba174ef' }
|
||||
- { name: Ruby 4.0 bazel 8, ruby: ruby-4.0.0, ffi: NATIVE, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.7.0-ruby-4.0.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }
|
||||
- { name: Ruby 4.0 bazel 8, ruby: ruby-4.4.4, ffi: FFI, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.7.0-ruby-4.0.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }
|
||||
- { name: JRuby 9.4, ruby: jruby-9.4.9.0, ffi: NATIVE }
|
||||
- { name: JRuby 9.4, ruby: jruby-9.4.9.0, ffi: FFI, continuous-only: true }
|
||||
- { name: JRuby 9.4 bazel 8, ruby: jruby-9.4.9.0, ffi: NATIVE, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.6.0-jruby-9.4.9.0-856ad422dddd3b8fbd85e36129496b37bba174ef' }
|
||||
- { name: JRuby 9.4 bazel 8, ruby: jruby-9.4.9.0, ffi: FFI, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.6.0-jruby-9.4.9.0-856ad422dddd3b8fbd85e36129496b37bba174ef' }
|
||||
- { name: JRuby 9.4 bazel 8, ruby: jruby-9.4.9.0, ffi: NATIVE, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.7.0-jruby-9.4.9.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }
|
||||
- { name: JRuby 9.4 bazel 8, ruby: jruby-9.4.9.0, ffi: FFI, image: 'us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:8.7.0-jruby-9.4.9.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }
|
||||
name: ${{ matrix.continuous-only && inputs.continuous-prefix || '' }} Install ${{ matrix.name }}${{ matrix.ffi == 'FFI' && ' FFI' || '' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
|
@ -210,7 +210,7 @@ jobs:
|
|||
if: ${{ !matrix.continuous-only || inputs.continuous-run }}
|
||||
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
|
||||
with:
|
||||
image: ${{ matrix.image || format('us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:9.0.0-{0}-9fc33a0c378b5affd3c85d3f5ae4f330993048f7', matrix.ruby) }}
|
||||
image: ${{ matrix.image || format('us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:9.2.0-{0}-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ', matrix.ruby) }}
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
bazel-cache: ruby_install/${{ matrix.ruby }}_${{ matrix.bazel }}
|
||||
bash: >
|
||||
|
|
|
|||
2
.github/workflows/test_rust.yml
vendored
2
.github/workflows/test_rust.yml
vendored
|
|
@ -24,7 +24,7 @@ jobs:
|
|||
|
||||
include:
|
||||
- targets: "//rust/... //src/google/protobuf/compiler/rust/..."
|
||||
- image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.0.0-9dca0d9417f43f5f1e97e59969fb0f3e6ae3bd9c"
|
||||
- image: "us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:9.2.0-4d8e80ef93b0219fb907af9dd4596b92946995d8"
|
||||
- bazel_cmd: "test"
|
||||
|
||||
# Override cases with custom images
|
||||
|
|
|
|||
6
.github/workflows/test_upb.yml
vendored
6
.github/workflows/test_upb.yml
vendored
|
|
@ -30,8 +30,8 @@ jobs:
|
|||
config:
|
||||
- { name: "Fastbuild" }
|
||||
- { name: "Optimized", flags: "-c opt", continuous-only: true }
|
||||
- { name: "GCC Optimized", flags: "-c opt --force_pic --java_runtime_version=remotejdk_11 --copt=\"-Wno-error=maybe-uninitialized\"", image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.0.1-12.2-12e21b8dda91028bc14212a3ab582c7c4d149fac" }
|
||||
- { name: "GCC Static", flags: "-c opt --dynamic_mode=off --java_runtime_version=remotejdk_11 --copt=\"-Wno-error=maybe-uninitialized\"", image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.0.1-12.2-12e21b8dda91028bc14212a3ab582c7c4d149fac", continuous-only: true }
|
||||
- { name: "GCC Optimized", flags: "-c opt --force_pic --java_runtime_version=remotejdk_11 --copt=\"-Wno-error=maybe-uninitialized\" --copt=\"-Wno-error=deprecated-declarations\" --copt=\"-Wno-error=array-bounds\"", image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.7.0-12.5-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 " }
|
||||
- { name: "GCC Static", flags: "-c opt --dynamic_mode=off --java_runtime_version=remotejdk_11 --copt=\"-Wno-error=maybe-uninitialized\" --copt=\"-Wno-error=deprecated-declarations\" --copt=\"-Wno-error=array-bounds\"", image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:8.7.0-12.5-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ", continuous-only: true }
|
||||
- { name: "ASAN", flags: "--config=asan -c dbg", exclude-targets: "-//benchmarks:benchmark -//python/...", runner: ubuntu-22-4core }
|
||||
- { name: "UBSAN", flags: "--config=ubsan -c dbg", exclude-targets: "-//benchmarks:benchmark -//python/... -//lua/...", continuous-only: true }
|
||||
- { name: "32-bit", flags: "--copt=-m32 --linkopt=-m32", exclude-targets: "-//benchmarks:benchmark -//python/..." }
|
||||
|
|
@ -51,7 +51,7 @@ jobs:
|
|||
if: ${{ !matrix.config.continuous-only || inputs.continuous-run }}
|
||||
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
|
||||
with:
|
||||
image: ${{ matrix.config.image || 'us-docker.pkg.dev/protobuf-build/containers/test/linux/sanitize:8.0.1-a6ca8ba8e77d63471b4ad05f8643e1fc58b30e12' }}
|
||||
image: ${{ matrix.config.image || 'us-docker.pkg.dev/protobuf-build/containers/test/linux/sanitize:8.7.0-5bb1a8fdfc30f8c21c1b38cf053d2db9fca865a7 ' }}
|
||||
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
|
||||
bazel-cache: upb-bazel
|
||||
bazel: test //benchmarks/... //lua/... //python/... //upb/... //upb_generator/... ${{ matrix.config.flags }}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ google/protobuf/compiler/php/names.h
|
|||
google/protobuf/compiler/plugin.h
|
||||
google/protobuf/compiler/plugin.pb.h
|
||||
google/protobuf/compiler/plugin.proto
|
||||
google/protobuf/compiler/python/names.h
|
||||
google/protobuf/compiler/retention.h
|
||||
google/protobuf/compiler/scc.h
|
||||
google/protobuf/compiler/subprocess.h
|
||||
|
|
@ -111,6 +112,7 @@ google/protobuf/metadata.h
|
|||
google/protobuf/metadata_lite.h
|
||||
google/protobuf/micro_string.h
|
||||
google/protobuf/naming_style.h
|
||||
google/protobuf/offset_ptr.h
|
||||
google/protobuf/option_interpreter.h
|
||||
google/protobuf/os_macros_restore.inc
|
||||
google/protobuf/os_macros_undef.inc
|
||||
|
|
@ -244,6 +246,7 @@ upb/wire/decode_fast/combinations.h
|
|||
upb/wire/decode_fast/data.h
|
||||
upb/wire/decode_fast/select.h
|
||||
upb/wire/encode.h
|
||||
upb/wire/encode_extension.h
|
||||
upb/wire/eps_copy_input_stream.h
|
||||
upb/wire/reader.h
|
||||
upb/wire/types.h
|
||||
|
|
|
|||
|
|
@ -499,6 +499,64 @@ void BinaryAndJsonConformanceSuite::RunMessageSetTests() {
|
|||
})pb"
|
||||
// clang-format on
|
||||
);
|
||||
|
||||
// [type_id, value, type_id (different)] -> first type_id and value honored.
|
||||
RunValidBinaryProtobufTest<TestAllTypesProto2>(
|
||||
absl::StrCat("ValidMessageSetEncoding.DuplicateDifferentTypeId"),
|
||||
RECOMMENDED,
|
||||
len(500,
|
||||
group(
|
||||
1,
|
||||
absl::StrCat(
|
||||
field(2, WireFormatLite::WIRETYPE_VARINT, varint(4135312)),
|
||||
len(3, field(9, WireFormatLite::WIRETYPE_VARINT, varint(99))),
|
||||
field(2, WireFormatLite::WIRETYPE_VARINT, varint(1547769))))),
|
||||
// clang-format off
|
||||
R"pb(message_set_correct: {
|
||||
[protobuf_test_messages.proto2
|
||||
.TestAllTypesProto2.MessageSetCorrectExtension2]: { i: 99 }
|
||||
})pb"
|
||||
// clang-format on
|
||||
);
|
||||
|
||||
// [type_id, value, value] -> first value honored, no merge.
|
||||
RunValidBinaryProtobufTest<TestAllTypesProto2>(
|
||||
absl::StrCat("ValidMessageSetEncoding.DuplicateValue"), RECOMMENDED,
|
||||
len(500,
|
||||
group(
|
||||
1,
|
||||
absl::StrCat(
|
||||
field(2, WireFormatLite::WIRETYPE_VARINT, varint(4135312)),
|
||||
len(3, field(9, WireFormatLite::WIRETYPE_VARINT, varint(99))),
|
||||
len(3,
|
||||
field(9, WireFormatLite::WIRETYPE_VARINT, varint(88)))))),
|
||||
// clang-format off
|
||||
R"pb(message_set_correct: {
|
||||
[protobuf_test_messages.proto2
|
||||
.TestAllTypesProto2.MessageSetCorrectExtension2]: { i: 99 }
|
||||
})pb"
|
||||
// clang-format on
|
||||
);
|
||||
|
||||
// [value, type_id, value] -> first value honored, no merge.
|
||||
RunValidBinaryProtobufTest<TestAllTypesProto2>(
|
||||
absl::StrCat("ValidMessageSetEncoding.DuplicateValueOutOfOrder"),
|
||||
RECOMMENDED,
|
||||
len(500,
|
||||
group(
|
||||
1,
|
||||
absl::StrCat(
|
||||
len(3, field(9, WireFormatLite::WIRETYPE_VARINT, varint(99))),
|
||||
field(2, WireFormatLite::WIRETYPE_VARINT, varint(4135312)),
|
||||
len(3,
|
||||
field(9, WireFormatLite::WIRETYPE_VARINT, varint(88)))))),
|
||||
// clang-format off
|
||||
R"pb(message_set_correct: {
|
||||
[protobuf_test_messages.proto2
|
||||
.TestAllTypesProto2.MessageSetCorrectExtension2]: { i: 99 }
|
||||
})pb"
|
||||
// clang-format on
|
||||
);
|
||||
}
|
||||
|
||||
void BinaryAndJsonConformanceSuite::RunRecursionLimitTests() {
|
||||
|
|
|
|||
|
|
@ -70,3 +70,6 @@ Required.*.ProtobufInput.BadTag_OverlongVarint
|
|||
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Oneof # Should have failed to parse, but didn't.
|
||||
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Repeated # Should have failed to parse, but didn't.
|
||||
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Singular # Should have failed to parse, but didn't.
|
||||
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateDifferentTypeId.ProtobufOutput # Output was not equivalent to reference message
|
||||
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateValue.ProtobufOutput # Output was not equivalent to reference message
|
||||
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateValueOutOfOrder.ProtobufOutput # Output was not equivalent to reference message
|
||||
|
|
|
|||
|
|
@ -15,3 +15,4 @@ Recommended.Editions.ProtobufInput.RejectInvalidUtf8.String.Extension
|
|||
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Oneof # Should have failed to parse, but didn't.
|
||||
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Repeated # Should have failed to parse, but didn't.
|
||||
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Singular # Should have failed to parse, but didn't.
|
||||
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateValue.ProtobufOutput # Output was not equivalent to reference message
|
||||
|
|
|
|||
|
|
@ -175,3 +175,6 @@ Required.*.JsonInput.TimestampJsonInputNonLeapFeb29
|
|||
Required.*.JsonInput.TimestampJsonInputSecondTooLarge # Should have failed to parse, but didn't.
|
||||
Required.*.JsonInput.TimestampJsonInputYearTooLong # Should have failed to parse, but didn't.
|
||||
Required.*.JsonInput.TimestampJsonInputYearTooShort # Should have failed to parse, but didn't.
|
||||
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateDifferentTypeId.ProtobufOutput # Output was not equivalent to reference message
|
||||
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateValue.ProtobufOutput # Output was not equivalent to reference message
|
||||
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateValueOutOfOrder.ProtobufOutput # Output was not equivalent to reference message
|
||||
|
|
|
|||
|
|
@ -3,4 +3,3 @@
|
|||
#
|
||||
# By listing them here we can keep tabs on which ones are failing and be sure
|
||||
# that we don't introduce regressions in other tests.
|
||||
Recommended.Proto2.ProtobufInput.EnforceDepthLimit.MessageSetExtension # Should have failed to parse, but didn't.
|
||||
|
|
|
|||
|
|
@ -35,3 +35,6 @@ Recommended.Proto3.ProtobufInput.RejectInvalidUtf8.String.Singular
|
|||
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Oneof # Should have failed to parse, but didn't.
|
||||
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Repeated # Should have failed to parse, but didn't.
|
||||
# Recommended.Proto2.ProtobufInput.RejectInvalidUtf8.String.Singular # Should have failed to parse, but didn't.
|
||||
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateDifferentTypeId.ProtobufOutput # Output was not equivalent to reference message
|
||||
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateValue.ProtobufOutput # Output was not equivalent to reference message
|
||||
Recommended.Proto2.ProtobufInput.ValidMessageSetEncoding.DuplicateValueOutOfOrder.ProtobufOutput # Output was not equivalent to reference message
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -598,3 +598,8 @@ about your project (name and website) so we can add an entry for you.
|
|||
|
||||
* Website: https://protowire.org
|
||||
* Extensions: 1314-1363
|
||||
|
||||
1. Flyte
|
||||
|
||||
* Website: https://github.com/flyteorg/flyte
|
||||
* Extensions: 1364-1373
|
||||
|
|
|
|||
|
|
@ -929,6 +929,15 @@ public final class Descriptors {
|
|||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this message type is defined in {@code descriptor.proto}.
|
||||
*
|
||||
* <p>For example, it returns true for {@code MessageOptions}, {@code FieldOptions}, etc.
|
||||
*/
|
||||
boolean isDescriptorProtoType() {
|
||||
return getFile() == DescriptorProtos.getDescriptor();
|
||||
}
|
||||
|
||||
public boolean isPlaceholder() {
|
||||
return placeholder;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1070,7 +1070,10 @@ class MessageReflection {
|
|||
Message defaultInstance)
|
||||
throws IOException {
|
||||
if (!field.isRepeated()) {
|
||||
boolean isLazyField = ExtensionRegistryLite.lazyExtensionEnabled() && field.isExtension();
|
||||
boolean isLazyField =
|
||||
ExtensionRegistryLite.lazyExtensionEnabled()
|
||||
&& field.isExtension()
|
||||
&& !field.getContainingType().isDescriptorProtoType();
|
||||
if (hasField(field)) {
|
||||
InternalLazyField lazyField = extensions.getLazyField(field);
|
||||
if (isLazyField && lazyField != null) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import static com.google.common.truth.Truth.assertWithMessage;
|
|||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import com.google.protobuf.ExtensionRegistryLite.LazyExtensionMode;
|
||||
import proto2_unittest.UnittestCustomOptions;
|
||||
import proto2_unittest.UnittestOptimizeFor;
|
||||
import proto2_unittest.UnittestOptimizeFor.TestOptimizedForSize;
|
||||
import proto2_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize;
|
||||
|
|
@ -459,4 +460,31 @@ public class ParserTest {
|
|||
|
||||
assertThat(builder.getExtension(TestParsingMerge.optionalExt).getOptionalInt32()).isEqualTo(2);
|
||||
}
|
||||
|
||||
// Test that custom options are eagerly parsed by verifying that an invalid tag in the extension
|
||||
// payload throws an exception.
|
||||
@Test
|
||||
public void testCustomOptionEagerlyParsed() throws Exception {
|
||||
LazyExtensionMode originalMode = ExtensionRegistryLite.getLazyExtensionMode();
|
||||
ExtensionRegistryLite.setLazyExtensionMode(LazyExtensionMode.LAZY_VERIFY_ON_ACCESS);
|
||||
int fieldNumber = UnittestCustomOptions.complexOpt1.getNumber();
|
||||
int extensionTag = (fieldNumber << 3) | 2; // WireFormat.WIRETYPE_LENGTH_DELIMITED
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
|
||||
codedOutput.writeUInt32NoTag(extensionTag);
|
||||
codedOutput.writeUInt32NoTag(1); // Length = 1 byte
|
||||
codedOutput.writeRawByte((byte) 0); // 0 is an invalid varint tag in protobuf payload
|
||||
codedOutput.flush();
|
||||
byte[] invalidPayload = output.toByteArray();
|
||||
ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
|
||||
registry.add(UnittestCustomOptions.complexOpt1);
|
||||
|
||||
Throwable thrown =
|
||||
assertThrows(
|
||||
InvalidProtocolBufferException.class,
|
||||
() -> DescriptorProtos.MessageOptions.parseFrom(invalidPayload, registry));
|
||||
|
||||
assertThat(thrown).hasMessageThat().contains("invalid tag");
|
||||
ExtensionRegistryLite.setLazyExtensionMode(originalMode);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class DslListTest {
|
|||
@Test
|
||||
fun dslListIsNotMutable() {
|
||||
val dslList = DslList<Int, DummyProxy>(mutableListOf(1, 2, 3))
|
||||
assertThat(dslList is MutableList<*>).isFalse()
|
||||
assertThat((dslList as Any) is MutableList<*>).isFalse()
|
||||
}
|
||||
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class DslMapTest {
|
|||
@Test
|
||||
fun dslMapIsNotMutable() {
|
||||
val dslMap = DslMap<Int, Int, DummyProxy>(mutableMapOf(1 to -1))
|
||||
assertThat(dslMap is MutableMap<*, *>).isFalse()
|
||||
assertThat((dslMap as Any) is MutableMap<*, *>).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class ExtensionListTest {
|
|||
TestProto.repeatedExtension,
|
||||
mutableListOf(1, 2, 3),
|
||||
)
|
||||
assertThat(extensionList is MutableList<*>).isFalse()
|
||||
assertThat((extensionList as Any) is MutableList<*>).isFalse()
|
||||
}
|
||||
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
|
||||
|
|
|
|||
|
|
@ -389,6 +389,29 @@ void GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state, int32_t
|
|||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data parentRecursionDepth:(NSUInteger)parentDepth {
|
||||
if ((self = [self initWithData:data])) {
|
||||
// The parent stream had already entered `parentDepth` nested parses; we
|
||||
// are about to begin one more level in this child stream, so seed the
|
||||
// depth accordingly and verify the limit before parsing starts. This
|
||||
// matches the convention used by the C++ ParseContext spawn helper,
|
||||
// which increments and checks the depth before recursing into a payload
|
||||
// that has been read into a fresh buffer.
|
||||
state_.recursionDepth = parentDepth + 1;
|
||||
@try {
|
||||
CheckRecursionLimit(&state_);
|
||||
} @catch (NSException *exception) {
|
||||
// If CheckRecursionLimit raises an exception (when recursion depth exceeds
|
||||
// kDefaultRecursionLimit), `self` will not be returned to the caller.
|
||||
// Explicitly release `self` here to avoid a memory leak before re-throwing.
|
||||
[self release];
|
||||
self = nil;
|
||||
@throw;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[buffer_ release];
|
||||
[super dealloc];
|
||||
|
|
|
|||
|
|
@ -33,6 +33,16 @@ typedef struct GPBCodedInputStreamState {
|
|||
NSData *buffer_;
|
||||
}
|
||||
|
||||
// Initializes a new stream over `data` whose initial recursion depth is one
|
||||
// deeper than `parentDepth`. Used when a parser needs to spawn a fresh
|
||||
// CodedInputStream to decode a payload that has already been read into a
|
||||
// separate buffer (e.g. MessageSet items), so that the native call stack
|
||||
// growth is still bounded by kDefaultRecursionLimit. The initializer raises
|
||||
// GPBCodedInputStreamErrorRecursionDepthExceeded if `parentDepth` is already
|
||||
// at the limit. Mirrors the depth-inheritance done by the C++ ParseContext
|
||||
// spawn helper.
|
||||
- (instancetype)initWithData:(NSData *)data parentRecursionDepth:(NSUInteger)parentDepth;
|
||||
|
||||
// Group support is deprecated, so we hide this interface from users, but
|
||||
// support for older data.
|
||||
- (void)readGroup:(int32_t)fieldNumber
|
||||
|
|
|
|||
|
|
@ -2444,7 +2444,16 @@ void GPBClearMessageAutocreator(GPBMessage *self) {
|
|||
[self setExtension:extension value:targetMessage];
|
||||
[targetMessage release];
|
||||
}
|
||||
GPBCodedInputStream *newInput = [[GPBCodedInputStream alloc] initWithData:rawBytes];
|
||||
// Parsing the MessageSet item payload requires a fresh CodedInputStream
|
||||
// because the payload bytes are read into a separate buffer before the
|
||||
// item's type-id and payload tags are correlated. Carry the parent
|
||||
// stream's recursion depth across to the child stream so that nested
|
||||
// MessageSet items (which would otherwise reset the depth to 0 on every
|
||||
// hop) remain bounded by kDefaultRecursionLimit. This mirrors the
|
||||
// depth-inheritance behavior of the C++ ParseContext spawn helper.
|
||||
GPBCodedInputStream *newInput =
|
||||
[[GPBCodedInputStream alloc] initWithData:rawBytes
|
||||
parentRecursionDepth:input->state_.recursionDepth];
|
||||
@try {
|
||||
[targetMessage mergeFromCodedInputStream:newInput
|
||||
extensionRegistry:extensionRegistry
|
||||
|
|
|
|||
|
|
@ -428,4 +428,81 @@ const int kUnknownTypeId2 = 1550056;
|
|||
}
|
||||
}
|
||||
|
||||
static NSData* MessageSetDataWithLayers(NSUInteger layers) {
|
||||
MSetMessage* innermost = [MSetMessage message];
|
||||
MSetMessageExtension1* innermostExt = [MSetMessageExtension1 message];
|
||||
innermostExt.i = 1;
|
||||
#if defined(GPB_UNITTEST_USE_C_FUNCTION_FOR_EXTENSIONS)
|
||||
[innermost setExtension:MSetMessageExtension1_extension_MessageSetExtension() value:innermostExt];
|
||||
#else
|
||||
[innermost setExtension:[MSetMessageExtension1 messageSetExtension] value:innermostExt];
|
||||
#endif
|
||||
|
||||
MSetMessage* current = innermost;
|
||||
for (NSUInteger i = 1; i < layers; ++i) {
|
||||
MSetMessageExtension1* ext = [MSetMessageExtension1 message];
|
||||
ext.recursive = current;
|
||||
MSetMessage* parent = [MSetMessage message];
|
||||
#if defined(GPB_UNITTEST_USE_C_FUNCTION_FOR_EXTENSIONS)
|
||||
[parent setExtension:MSetMessageExtension1_extension_MessageSetExtension() value:ext];
|
||||
#else
|
||||
[parent setExtension:[MSetMessageExtension1 messageSetExtension] value:ext];
|
||||
#endif
|
||||
current = parent;
|
||||
}
|
||||
return [current data];
|
||||
}
|
||||
|
||||
- (void)testParseMessageSetRecursionDepthCarriedFromParent {
|
||||
// Each MSetMessage carries a single MSetMessageExtension1, whose
|
||||
// `recursive` field is again a MSetMessage. Chaining N of these produces
|
||||
// a MessageSet-of-MessageSet payload nested N levels deep. The parser
|
||||
// for each MessageSet item allocates a fresh CodedInputStream, so depth
|
||||
// tracking has to be inherited across those streams for the documented
|
||||
// kDefaultRecursionLimit (100) to actually apply.
|
||||
//
|
||||
// Each layer increases recursion depth by 2 (+1 for the child CodedInputStream
|
||||
// in parseMessageSet:, +1 for the `recursive` message field in readMessage:).
|
||||
// 50 layers reaches depth 100 (kDefaultRecursionLimit), which must parse successfully.
|
||||
// 51 layers attempts to reach depth 101 (kDefaultRecursionLimit + 1), which must fail
|
||||
// with GPBCodedInputStreamErrorRecursionDepthExceeded rather than silently parsing.
|
||||
const NSUInteger kPassLayers = 50;
|
||||
NSData* passData = MessageSetDataWithLayers(kPassLayers);
|
||||
XCTAssertNotNil(passData);
|
||||
|
||||
NSError* error = nil;
|
||||
#if defined(GPB_UNITTEST_USE_C_FUNCTION_FOR_EXTENSIONS)
|
||||
MSetMessage* passParsed =
|
||||
[MSetMessage parseFromData:passData
|
||||
extensionRegistry:MSet_Objc_Protobuf_Tests_Mset_MSetUnittestMsetRoot_Registry()
|
||||
error:&error];
|
||||
#else
|
||||
MSetMessage* passParsed = [MSetMessage parseFromData:passData
|
||||
extensionRegistry:[MSetUnittestMsetRoot extensionRegistry]
|
||||
error:&error];
|
||||
#endif
|
||||
XCTAssertNotNil(passParsed);
|
||||
XCTAssertNil(error);
|
||||
|
||||
const NSUInteger kFailLayers = 51;
|
||||
NSData* failData = MessageSetDataWithLayers(kFailLayers);
|
||||
XCTAssertNotNil(failData);
|
||||
|
||||
error = nil;
|
||||
#if defined(GPB_UNITTEST_USE_C_FUNCTION_FOR_EXTENSIONS)
|
||||
MSetMessage* failParsed =
|
||||
[MSetMessage parseFromData:failData
|
||||
extensionRegistry:MSet_Objc_Protobuf_Tests_Mset_MSetUnittestMsetRoot_Registry()
|
||||
error:&error];
|
||||
#else
|
||||
MSetMessage* failParsed = [MSetMessage parseFromData:failData
|
||||
extensionRegistry:[MSetUnittestMsetRoot extensionRegistry]
|
||||
error:&error];
|
||||
#endif
|
||||
XCTAssertNil(failParsed);
|
||||
XCTAssertNotNil(error);
|
||||
XCTAssertEqualObjects(error.domain, GPBCodedInputStreamErrorDomain);
|
||||
XCTAssertEqual(error.code, GPBCodedInputStreamErrorRecursionDepthExceeded);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -6413,6 +6413,9 @@ static upb_Arena* jsonenc_arena(jsonenc* e) {
|
|||
/* Create lazily, since it's only needed for Any */
|
||||
if (!e->arena) {
|
||||
e->arena = upb_Arena_New();
|
||||
if (!e->arena) {
|
||||
jsonenc_err(e, "Out of memory");
|
||||
}
|
||||
}
|
||||
return e->arena;
|
||||
}
|
||||
|
|
@ -6730,6 +6733,10 @@ static void jsonenc_any(jsonenc* e, const upb_Message* msg,
|
|||
const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m);
|
||||
upb_Arena* arena = jsonenc_arena(e);
|
||||
upb_Message* any = upb_Message_New(any_layout, arena);
|
||||
if (!any) {
|
||||
jsonenc_err(e, "Out of memory");
|
||||
return;
|
||||
}
|
||||
|
||||
if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) !=
|
||||
kUpb_DecodeStatus_Ok) {
|
||||
|
|
@ -9112,26 +9119,6 @@ void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) {
|
|||
in->size = size;
|
||||
}
|
||||
|
||||
upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown(upb_Message* msg,
|
||||
upb_StringView* data,
|
||||
uintptr_t* iter,
|
||||
upb_Arena* arena) {
|
||||
upb_MessageUnknown unknown;
|
||||
unknown.type = kUpb_MessageUnknownType_StringView;
|
||||
unknown.value.bytes = *data;
|
||||
|
||||
upb_Message_DeleteUnknownStatus res =
|
||||
upb_Message_DeleteUnknown2(msg, &unknown, iter, arena);
|
||||
UPB_ASSERT(unknown.type == kUpb_MessageUnknownType_StringView);
|
||||
if (res == kUpb_DeleteUnknown_IterUpdated ||
|
||||
res == kUpb_DeleteUnknown_DeletedLast) {
|
||||
// the unknown data remains the same on the result of
|
||||
// kUpb_DeleteUnknown_AllocFail.
|
||||
*data = unknown.value.bytes;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t upb_Message_ExtensionCount(const upb_Message* msg) {
|
||||
upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
|
||||
if (!in) return 0;
|
||||
|
|
@ -9352,6 +9339,25 @@ upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown2(
|
|||
: kUpb_DeleteUnknown_DeletedLast;
|
||||
}
|
||||
|
||||
upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown(
|
||||
struct upb_Message* msg, upb_StringView* data, uintptr_t* iter,
|
||||
struct upb_Arena* arena) {
|
||||
upb_MessageUnknown unknown;
|
||||
unknown.type = kUpb_MessageUnknownType_StringView;
|
||||
unknown.value.bytes = *data;
|
||||
|
||||
upb_Message_DeleteUnknownStatus res =
|
||||
upb_Message_DeleteUnknown2(msg, &unknown, iter, arena);
|
||||
UPB_ASSERT(unknown.type == kUpb_MessageUnknownType_StringView);
|
||||
if (res == kUpb_DeleteUnknown_IterUpdated ||
|
||||
res == kUpb_DeleteUnknown_DeletedLast) {
|
||||
// the unknown data remains the same on the result of
|
||||
// kUpb_DeleteUnknown_AllocFail.
|
||||
*data = unknown.value.bytes;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
|
@ -10287,12 +10293,21 @@ upb_Extension* UPB_PRIVATE(_upb_Message_GetOrCreateExtensionWithTag)(
|
|||
struct upb_Message* msg, const upb_MiniTableExtension* e, upb_Arena* a,
|
||||
upb_TaggedAuxType tag) {
|
||||
UPB_ASSERT(!upb_Message_IsFrozen(msg));
|
||||
upb_Extension* ext = (upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e);
|
||||
if (ext) return ext;
|
||||
|
||||
// For Canonical Extensions, we check whether the extension has already been
|
||||
// set. If we find an extension with the same pointer and tag, we reuse it to
|
||||
// prevent duplicate entries for the same extension.
|
||||
//
|
||||
// For Non-Canonical Extensions, we do NOT reuse them, matching the behavior
|
||||
// of adding a unknown StringView (through `_upb_Message_AddUnknown`) which
|
||||
// accumulates.
|
||||
if (tag == kUpb_TaggedAuxType_CanonicalExtension) {
|
||||
upb_Extension* ext =
|
||||
(upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e);
|
||||
if (ext) return ext;
|
||||
}
|
||||
if (!UPB_PRIVATE(_upb_Message_ReserveSlot)(msg, a)) return NULL;
|
||||
upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
|
||||
ext = upb_Arena_Malloc(a, sizeof(upb_Extension));
|
||||
upb_Extension* ext = upb_Arena_Malloc(a, sizeof(upb_Extension));
|
||||
if (!ext) return NULL;
|
||||
memset(ext, 0, sizeof(upb_Extension));
|
||||
ext->ext = e;
|
||||
|
|
@ -11382,6 +11397,7 @@ done:
|
|||
#endif
|
||||
|
||||
upb_MiniTable* ret = upb_Arena_Malloc(decoder->arena, mt_size);
|
||||
upb_MdDecoder_CheckOutOfMemory(&decoder->base, ret);
|
||||
memcpy(ret, &decoder->table, sizeof(*ret));
|
||||
|
||||
#if UPB_FASTTABLE
|
||||
|
|
@ -18340,6 +18356,49 @@ const char* upb_EncodeStatus_String(upb_EncodeStatus status) {
|
|||
}
|
||||
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
// Must be last.
|
||||
|
||||
static upb_EncodeStatus upb_DoEncodeExtension(upb_encstate* encoder, char* ptr,
|
||||
const struct upb_Extension* ext,
|
||||
bool is_message_set,
|
||||
upb_StringView* view,
|
||||
int encode_options) {
|
||||
if (UPB_SETJMP(*encoder->err) == 0) {
|
||||
char* buf = ptr;
|
||||
size_t size = 0;
|
||||
UPB_PRIVATE(_upb_Encode_Extension)(encoder, ext->ext, ext->data,
|
||||
is_message_set, &buf, &size,
|
||||
encode_options);
|
||||
view->data = buf;
|
||||
view->size = size;
|
||||
} else {
|
||||
UPB_ASSERT(encoder->status != kUpb_EncodeStatus_Ok);
|
||||
upb_BackAlloc_Abort(&encoder->alloc);
|
||||
view->data = NULL;
|
||||
view->size = 0;
|
||||
}
|
||||
UPB_PRIVATE(_upb_encstate_destroy)(encoder);
|
||||
return encoder->status;
|
||||
}
|
||||
|
||||
upb_EncodeStatus upb_EncodeExtension(const struct upb_Extension* ext,
|
||||
struct upb_Arena* arena,
|
||||
upb_StringView* view, int encode_options) {
|
||||
const upb_MiniTable* extendee = upb_MiniTableExtension_Extendee(ext->ext);
|
||||
bool is_message_set =
|
||||
extendee != NULL && upb_MiniTable_IsMessageSet(extendee);
|
||||
upb_encstate e;
|
||||
jmp_buf err;
|
||||
char* ptr = UPB_PRIVATE(_upb_encstate_init)(&e, &err, arena);
|
||||
return upb_DoEncodeExtension(&e, ptr, ext, is_message_set, view,
|
||||
encode_options);
|
||||
}
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
|
@ -19026,9 +19085,12 @@ static char* encode_map(char* ptr, upb_encstate* e, const upb_Message* msg,
|
|||
|
||||
if (e->options & kUpb_EncodeOption_Deterministic) {
|
||||
_upb_sortedmap sorted;
|
||||
_upb_mapsorter_pushmap(
|
||||
&e->sorter, layout->UPB_PRIVATE(fields)[0].UPB_PRIVATE(descriptortype),
|
||||
map, &sorted);
|
||||
if (!_upb_mapsorter_pushmap(
|
||||
&e->sorter,
|
||||
layout->UPB_PRIVATE(fields)[0].UPB_PRIVATE(descriptortype), map,
|
||||
&sorted)) {
|
||||
encode_err(e, kUpb_EncodeStatus_OutOfMemory);
|
||||
}
|
||||
upb_MapEntry ent;
|
||||
while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) {
|
||||
ptr = encode_mapentry(ptr, e, upb_MiniTableField_Number(f), layout, &ent);
|
||||
|
|
@ -19164,7 +19226,7 @@ static char* encode_exts(char* ptr, upb_encstate* e, const upb_MiniTable* m,
|
|||
if (e->options & kUpb_EncodeOption_Deterministic) {
|
||||
_upb_sortedmap sorted;
|
||||
if (!_upb_mapsorter_pushexts(&e->sorter, in, &sorted)) {
|
||||
// TODO: b/378744096 - handle alloc failure
|
||||
encode_err(e, kUpb_EncodeStatus_OutOfMemory);
|
||||
}
|
||||
const upb_Extension* ext;
|
||||
while (_upb_sortedmap_nextext(&e->sorter, &sorted, &ext)) {
|
||||
|
|
|
|||
|
|
@ -5711,139 +5711,6 @@ UPB_API_INLINE bool upb_Map_IsFrozen(const upb_Map* map);
|
|||
#include <stdint.h>
|
||||
|
||||
|
||||
#ifndef UPB_MESSAGE_UNKNOWN_FIELDS_H_
|
||||
#define UPB_MESSAGE_UNKNOWN_FIELDS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// Must be last.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct upb_Extension;
|
||||
|
||||
typedef enum {
|
||||
kUpb_MessageUnknownType_StringView,
|
||||
kUpb_MessageUnknownType_NonCanonicalExtension,
|
||||
} upb_MessageUnknownType;
|
||||
|
||||
// Represents an unknown field in a message, whether it's in a serialized
|
||||
// (upb_StringView) or parsed non-canonical extension (upb_Extension*) format.
|
||||
typedef struct upb_MessageUnknown {
|
||||
uint8_t type;
|
||||
union {
|
||||
upb_StringView bytes;
|
||||
const upb_Extension* extension;
|
||||
} value;
|
||||
} upb_MessageUnknown;
|
||||
|
||||
// Support iteration over unknown (upb_MessageUnknown*), including unknown
|
||||
// upb_StringView and non-canonical extensions (upb_Extension*).
|
||||
UPB_INLINE bool upb_Message_NextUnknown2(const struct upb_Message* msg,
|
||||
struct upb_MessageUnknown* data,
|
||||
uintptr_t* iter) {
|
||||
const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
|
||||
size_t i = *iter;
|
||||
if (in) {
|
||||
while (i < in->size) {
|
||||
upb_TaggedAuxPtr tagged_ptr = in->aux_data[i++];
|
||||
if (upb_TaggedAuxPtr_IsUnknownStringView(tagged_ptr)) {
|
||||
data->type = kUpb_MessageUnknownType_StringView;
|
||||
data->value.bytes = *upb_TaggedPtrAux_StringViewRepr(tagged_ptr);
|
||||
*iter = i;
|
||||
return true;
|
||||
} else if (upb_TaggedAuxPtr_IsNonCanonicalExtension(tagged_ptr)) {
|
||||
data->type = kUpb_MessageUnknownType_NonCanonicalExtension;
|
||||
data->value.extension =
|
||||
upb_TaggedAuxPtr_NonCanonicalExtension(tagged_ptr);
|
||||
*iter = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
data->type = kUpb_MessageUnknownType_StringView;
|
||||
data->value.bytes.size = 0;
|
||||
data->value.bytes.data = NULL;
|
||||
*iter = i;
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
kUpb_FindUnknown_Ok,
|
||||
kUpb_FindUnknown_NotPresent,
|
||||
kUpb_FindUnknown_ParseError,
|
||||
} upb_FindUnknown_Status;
|
||||
|
||||
typedef struct {
|
||||
upb_FindUnknown_Status status;
|
||||
struct upb_MessageUnknown unknown;
|
||||
uintptr_t iter;
|
||||
} upb_FindUnknownRet2;
|
||||
|
||||
// Finds first occurrence of unknown data (upb_MessageUnknown) by tag id in
|
||||
// message, including unknown upb_StringView and non-canonical extensions
|
||||
// (upb_Extension*).
|
||||
//
|
||||
// If multiple matching entries exist for the same field number (e.g. both a
|
||||
// raw unknown upb_StringView and a non-canonical extension), this function
|
||||
// returns the one encountered first in internal iteration order (which follows
|
||||
// the order they were added or parsed).
|
||||
//
|
||||
// A depth_limit of zero means to just use the upb default depth limit.
|
||||
upb_FindUnknownRet2 upb_Message_FindUnknown2(const struct upb_Message* msg,
|
||||
uint32_t field_number,
|
||||
int depth_limit);
|
||||
|
||||
typedef enum {
|
||||
kUpb_DeleteUnknown_DeletedLast,
|
||||
kUpb_DeleteUnknown_IterUpdated,
|
||||
kUpb_DeleteUnknown_AllocFail,
|
||||
} upb_Message_DeleteUnknownStatus;
|
||||
|
||||
// Removes a segment of unknown data from the message, advancing to the next
|
||||
// segment. Returns false if the removed segment was at the end of the last
|
||||
// chunk.
|
||||
//
|
||||
// This must be done while iterating:
|
||||
//
|
||||
// uintptr_t iter = kUpb_Message_UnknownBegin;
|
||||
// upb_MessageUnknown data;
|
||||
// // Iterate chunks
|
||||
// while (upb_Message_NextUnknown2(msg, &data, &iter)) {
|
||||
// // Iterate within a chunk, deleting ranges
|
||||
// while (ShouldDeleteSubSegment(&data)) {
|
||||
// // Data now points to the region to be deleted
|
||||
// switch (upb_Message_DeleteUnknown2(msg, &data, &iter)) {
|
||||
// case kUpb_DeleteUnknown_DeletedLast: return ok;
|
||||
// case kUpb_DeleteUnknown_IterUpdated: break;
|
||||
// // If DeleteUnknown returned kUpb_DeleteUnknown_IterUpdated,
|
||||
// // then data now points to the remaining unknown fields after the
|
||||
// // region that was just deleted.
|
||||
// case kUpb_Message_DeleteUnknown_AllocFail: return err;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// The range given in `data` must be contained inside the most recently
|
||||
// returned region.
|
||||
//
|
||||
// Support deletion of unknown (upb_MessageUnknown*), including unknown
|
||||
// upb_StringView and non-canonical extensions (upb_Extension*).
|
||||
UPB_NODISCARD upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown2(
|
||||
struct upb_Message* msg, struct upb_MessageUnknown* data, uintptr_t* iter,
|
||||
struct upb_Arena* arena);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* UPB_MESSAGE_UNKNOWN_FIELDS_H_ */
|
||||
|
||||
// Must be last.
|
||||
|
||||
typedef struct upb_Message upb_Message;
|
||||
|
|
@ -5889,39 +5756,6 @@ UPB_INLINE bool upb_Message_HasUnknown(const upb_Message* msg) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Removes a segment of unknown data from the message, advancing to the next
|
||||
// segment. Returns false if the removed segment was at the end of the last
|
||||
// chunk.
|
||||
//
|
||||
// This must be done while iterating:
|
||||
//
|
||||
// uintptr_t iter = kUpb_Message_UnknownBegin;
|
||||
// upb_StringView data;
|
||||
// // Iterate chunks
|
||||
// while (upb_Message_NextUnknown(msg, &data, &iter)) {
|
||||
// // Iterate within a chunk, deleting ranges
|
||||
// while (ShouldDeleteSubSegment(&data)) {
|
||||
// // Data now points to the region to be deleted
|
||||
// switch (upb_Message_DeleteUnknown(msg, &data, &iter)) {
|
||||
// case kUpb_Message_DeleteUnknown_DeletedLast: return ok;
|
||||
// case kUpb_Message_DeleteUnknown_IterUpdated: break;
|
||||
// // If DeleteUnknown returned kUpb_Message_DeleteUnknown_IterUpdated,
|
||||
// // then data now points to the remaining unknown fields after the
|
||||
// // region that was just deleted.
|
||||
// case kUpb_Message_DeleteUnknown_AllocFail: return err;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// The range given in `data` must be contained inside the most recently
|
||||
// returned region.
|
||||
//
|
||||
// TODO: b/510055656 - Legacy API that works with messages that only have
|
||||
// unknown data in upb_StringView format. Use `upb_Message_DeleteUnknown2` for
|
||||
// messages that may have non-canonical extensions.
|
||||
UPB_NODISCARD upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown(
|
||||
upb_Message* msg, upb_StringView* data, uintptr_t* iter, upb_Arena* arena);
|
||||
|
||||
// Returns the number of extensions present in this message.
|
||||
size_t upb_Message_ExtensionCount(const upb_Message* msg);
|
||||
|
||||
|
|
@ -16890,6 +16724,170 @@ bool _upb_mapsorter_pushexts(_upb_mapsorter* s, const upb_Message_Internal* in,
|
|||
|
||||
#endif /* UPB_MESSAGE_INTERNAL_MAP_SORTER_H_ */
|
||||
|
||||
#ifndef UPB_MESSAGE_UNKNOWN_FIELDS_H_
|
||||
#define UPB_MESSAGE_UNKNOWN_FIELDS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// Must be last.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
kUpb_MessageUnknownType_StringView,
|
||||
kUpb_MessageUnknownType_NonCanonicalExtension,
|
||||
} upb_MessageUnknownType;
|
||||
|
||||
// Represents an unknown field in a message, whether it's in a serialized
|
||||
// (upb_StringView) or parsed non-canonical extension (upb_Extension*) format.
|
||||
typedef struct upb_MessageUnknown {
|
||||
uint8_t type;
|
||||
union {
|
||||
upb_StringView bytes;
|
||||
const upb_Extension* extension;
|
||||
} value;
|
||||
} upb_MessageUnknown;
|
||||
|
||||
// Support iteration over unknown (upb_MessageUnknown*), including unknown
|
||||
// upb_StringView and non-canonical extensions (upb_Extension*).
|
||||
UPB_INLINE bool upb_Message_NextUnknown2(const struct upb_Message* msg,
|
||||
struct upb_MessageUnknown* data,
|
||||
uintptr_t* iter) {
|
||||
const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
|
||||
size_t i = *iter;
|
||||
if (in) {
|
||||
while (i < in->size) {
|
||||
upb_TaggedAuxPtr tagged_ptr = in->aux_data[i++];
|
||||
if (upb_TaggedAuxPtr_IsUnknownStringView(tagged_ptr)) {
|
||||
data->type = kUpb_MessageUnknownType_StringView;
|
||||
data->value.bytes = *upb_TaggedPtrAux_StringViewRepr(tagged_ptr);
|
||||
*iter = i;
|
||||
return true;
|
||||
} else if (upb_TaggedAuxPtr_IsNonCanonicalExtension(tagged_ptr)) {
|
||||
data->type = kUpb_MessageUnknownType_NonCanonicalExtension;
|
||||
data->value.extension =
|
||||
upb_TaggedAuxPtr_NonCanonicalExtension(tagged_ptr);
|
||||
*iter = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
data->type = kUpb_MessageUnknownType_StringView;
|
||||
data->value.bytes.size = 0;
|
||||
data->value.bytes.data = NULL;
|
||||
*iter = i;
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
kUpb_FindUnknown_Ok,
|
||||
kUpb_FindUnknown_NotPresent,
|
||||
kUpb_FindUnknown_ParseError,
|
||||
} upb_FindUnknown_Status;
|
||||
|
||||
typedef struct {
|
||||
upb_FindUnknown_Status status;
|
||||
struct upb_MessageUnknown unknown;
|
||||
uintptr_t iter;
|
||||
} upb_FindUnknownRet2;
|
||||
|
||||
// Finds first occurrence of unknown data (upb_MessageUnknown) by tag id in
|
||||
// message, including unknown upb_StringView and non-canonical extensions
|
||||
// (upb_Extension*).
|
||||
//
|
||||
// If multiple matching entries exist for the same field number (e.g. both a
|
||||
// raw unknown upb_StringView and a non-canonical extension), this function
|
||||
// returns the one encountered first in internal iteration order (which follows
|
||||
// the order they were added or parsed).
|
||||
//
|
||||
// A depth_limit of zero means to just use the upb default depth limit.
|
||||
upb_FindUnknownRet2 upb_Message_FindUnknown2(const struct upb_Message* msg,
|
||||
uint32_t field_number,
|
||||
int depth_limit);
|
||||
|
||||
typedef enum {
|
||||
kUpb_DeleteUnknown_DeletedLast,
|
||||
kUpb_DeleteUnknown_IterUpdated,
|
||||
kUpb_DeleteUnknown_AllocFail,
|
||||
} upb_Message_DeleteUnknownStatus;
|
||||
|
||||
// Removes a segment of unknown data from the message, advancing to the next
|
||||
// segment. Returns false if the removed segment was at the end of the last
|
||||
// chunk.
|
||||
//
|
||||
// This must be done while iterating:
|
||||
//
|
||||
// uintptr_t iter = kUpb_Message_UnknownBegin;
|
||||
// upb_StringView data;
|
||||
// // Iterate chunks
|
||||
// while (upb_Message_NextUnknown(msg, &data, &iter)) {
|
||||
// // Iterate within a chunk, deleting ranges
|
||||
// while (ShouldDeleteSubSegment(&data)) {
|
||||
// // Data now points to the region to be deleted
|
||||
// switch (upb_Message_DeleteUnknown(msg, &data, &iter)) {
|
||||
// case kUpb_DeleteUnknown_DeletedLast: return ok;
|
||||
// case kUpb_DeleteUnknown_IterUpdated: break;
|
||||
// // If DeleteUnknown returned kUpb_DeleteUnknown_IterUpdated,
|
||||
// // then data now points to the remaining unknown fields after the
|
||||
// // region that was just deleted.
|
||||
// case kUpb_DeleteUnknown_AllocFail: return err;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// The range given in `data` must be contained inside the most recently
|
||||
// returned region.
|
||||
// TODO: b/510055656 - Legacy API that works with messages that only have
|
||||
// unknown data in upb_StringView format. Use `upb_Message_DeleteUnknown2` for
|
||||
// messages that may have non-canonical extensions.
|
||||
UPB_NODISCARD upb_Message_DeleteUnknownStatus
|
||||
upb_Message_DeleteUnknown(struct upb_Message* msg, upb_StringView* data,
|
||||
uintptr_t* iter, struct upb_Arena* arena);
|
||||
|
||||
// Removes a segment of unknown data from the message, advancing to the next
|
||||
// segment. Returns false if the removed segment was at the end of the last
|
||||
// chunk.
|
||||
//
|
||||
// This must be done while iterating:
|
||||
//
|
||||
// uintptr_t iter = kUpb_Message_UnknownBegin;
|
||||
// upb_MessageUnknown data;
|
||||
// // Iterate chunks
|
||||
// while (upb_Message_NextUnknown2(msg, &data, &iter)) {
|
||||
// // Iterate within a chunk, deleting ranges
|
||||
// while (ShouldDeleteSubSegment(&data)) {
|
||||
// // Data now points to the region to be deleted
|
||||
// switch (upb_Message_DeleteUnknown2(msg, &data, &iter)) {
|
||||
// case kUpb_DeleteUnknown_DeletedLast: return ok;
|
||||
// case kUpb_DeleteUnknown_IterUpdated: break;
|
||||
// // If DeleteUnknown returned kUpb_DeleteUnknown_IterUpdated,
|
||||
// // then data now points to the remaining unknown fields after the
|
||||
// // region that was just deleted.
|
||||
// case kUpb_DeleteUnknown_AllocFail: return err;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// The range given in `data` must be contained inside the most recently
|
||||
// returned region.
|
||||
//
|
||||
// Support deletion of unknown (upb_MessageUnknown*), including unknown
|
||||
// upb_StringView and non-canonical extensions (upb_Extension*).
|
||||
UPB_NODISCARD upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown2(
|
||||
struct upb_Message* msg, struct upb_MessageUnknown* data, uintptr_t* iter,
|
||||
struct upb_Arena* arena);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* UPB_MESSAGE_UNKNOWN_FIELDS_H_ */
|
||||
|
||||
#ifndef UPB_WIRE_EPS_COPY_INPUT_STREAM_H_
|
||||
#define UPB_WIRE_EPS_COPY_INPUT_STREAM_H_
|
||||
|
||||
|
|
@ -19476,6 +19474,33 @@ void _upb_Decoder_AddEnumValueToUnknown(upb_Decoder* d, upb_Message* msg,
|
|||
|
||||
|
||||
#endif /* UPB_WIRE_INTERNAL_DECODER_H_ */
|
||||
|
||||
#ifndef UPB_WIRE_ENCODE_EXTENSION_H_
|
||||
#define UPB_WIRE_ENCODE_EXTENSION_H_
|
||||
|
||||
|
||||
// Must be last.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct upb_Extension;
|
||||
|
||||
// Encodes an extension (`upb_Extension*`) to bytes.
|
||||
//
|
||||
// This can be used to encode an extension into the provided arena.
|
||||
// Returns `kUpb_EncodeStatus_Ok` on success.
|
||||
UPB_NODISCARD upb_EncodeStatus
|
||||
upb_EncodeExtension(const struct upb_Extension* ext, struct upb_Arena* arena,
|
||||
upb_StringView* view, int encode_options);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* UPB_WIRE_ENCODE_EXTENSION_H_ */
|
||||
#ifndef GOOGLE_UPB_UPB_WIRE_WRITER_H__
|
||||
#define GOOGLE_UPB_UPB_WIRE_WRITER_H__
|
||||
|
||||
|
|
|
|||
|
|
@ -222,6 +222,7 @@ cc_dist_library(
|
|||
"//src/google/protobuf/compiler/java:names",
|
||||
"//src/google/protobuf/compiler/objectivec:names",
|
||||
"//src/google/protobuf/compiler/php:names",
|
||||
"//src/google/protobuf/compiler/python:names",
|
||||
],
|
||||
)
|
||||
|
||||
|
|
@ -242,6 +243,7 @@ cc_dist_library(
|
|||
"//upb/util:def_to_proto",
|
||||
"//upb/util:required_fields",
|
||||
"//upb/wire:byte_size",
|
||||
"//upb/wire:encode_extension",
|
||||
"//upb/wire/decode_fast:select",
|
||||
],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,12 @@ static upb_StringView Convert_StringData(VALUE str, upb_Arena* arena) {
|
|||
memcpy(ptr, RSTRING_PTR(str), RSTRING_LEN(str));
|
||||
ret.data = ptr;
|
||||
} else {
|
||||
// Data is only needed temporarily (within map lookup).
|
||||
// Alias the Ruby String's bytes instead of copying them. Only valid when
|
||||
// the result is consumed before anything can allocate: Convert_RubyToUpb
|
||||
// may have converted `str` to a temporary that nothing else references, so
|
||||
// any GC between here and the read can free or move it. The map lookup
|
||||
// paths (Map_index, Map_has_key, Map_delete) satisfy this; insertion paths
|
||||
// must pass an arena.
|
||||
ret.data = RSTRING_PTR(str);
|
||||
}
|
||||
ret.size = RSTRING_LEN(str);
|
||||
|
|
|
|||
|
|
@ -434,8 +434,13 @@ static VALUE Map_index(VALUE _self, VALUE key) {
|
|||
static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) {
|
||||
Map* self = ruby_to_Map(_self);
|
||||
upb_Arena* arena = Arena_get(self->arena);
|
||||
// The key must be copied into the arena, not aliased. Converting the value
|
||||
// below can allocate a Ruby object and therefore trigger GC, which may free
|
||||
// or move the String the key would otherwise point into. Passing NULL here is
|
||||
// only safe when the key is consumed before any allocation, as in the lookup
|
||||
// paths (Map_index, Map_has_key, Map_delete).
|
||||
upb_MessageValue key_upb =
|
||||
Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
|
||||
Convert_RubyToUpb(key, "", Map_keyinfo(self), arena);
|
||||
upb_MessageValue val_upb =
|
||||
Convert_RubyToUpb(val, "", self->value_type_info, arena);
|
||||
|
||||
|
|
|
|||
|
|
@ -527,7 +527,10 @@ typedef struct {
|
|||
static int Map_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
|
||||
MapInit* map_init = (MapInit*)_self;
|
||||
upb_MessageValue k, v;
|
||||
k = Convert_RubyToUpb(key, "", map_init->key_type, NULL);
|
||||
// Copy the key into the arena rather than aliasing it: building the value
|
||||
// below allocates, which can trigger GC and free or move the String the key
|
||||
// would otherwise point into.
|
||||
k = Convert_RubyToUpb(key, "", map_init->key_type, map_init->arena);
|
||||
|
||||
if (map_init->val_type.type == kUpb_CType_Message && TYPE(val) == T_HASH) {
|
||||
const upb_MiniTable* t =
|
||||
|
|
|
|||
|
|
@ -5166,6 +5166,9 @@ static upb_Arena* jsonenc_arena(jsonenc* e) {
|
|||
/* Create lazily, since it's only needed for Any */
|
||||
if (!e->arena) {
|
||||
e->arena = upb_Arena_New();
|
||||
if (!e->arena) {
|
||||
jsonenc_err(e, "Out of memory");
|
||||
}
|
||||
}
|
||||
return e->arena;
|
||||
}
|
||||
|
|
@ -5483,6 +5486,10 @@ static void jsonenc_any(jsonenc* e, const upb_Message* msg,
|
|||
const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m);
|
||||
upb_Arena* arena = jsonenc_arena(e);
|
||||
upb_Message* any = upb_Message_New(any_layout, arena);
|
||||
if (!any) {
|
||||
jsonenc_err(e, "Out of memory");
|
||||
return;
|
||||
}
|
||||
|
||||
if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) !=
|
||||
kUpb_DecodeStatus_Ok) {
|
||||
|
|
@ -7865,26 +7872,6 @@ void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) {
|
|||
in->size = size;
|
||||
}
|
||||
|
||||
upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown(upb_Message* msg,
|
||||
upb_StringView* data,
|
||||
uintptr_t* iter,
|
||||
upb_Arena* arena) {
|
||||
upb_MessageUnknown unknown;
|
||||
unknown.type = kUpb_MessageUnknownType_StringView;
|
||||
unknown.value.bytes = *data;
|
||||
|
||||
upb_Message_DeleteUnknownStatus res =
|
||||
upb_Message_DeleteUnknown2(msg, &unknown, iter, arena);
|
||||
UPB_ASSERT(unknown.type == kUpb_MessageUnknownType_StringView);
|
||||
if (res == kUpb_DeleteUnknown_IterUpdated ||
|
||||
res == kUpb_DeleteUnknown_DeletedLast) {
|
||||
// the unknown data remains the same on the result of
|
||||
// kUpb_DeleteUnknown_AllocFail.
|
||||
*data = unknown.value.bytes;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t upb_Message_ExtensionCount(const upb_Message* msg) {
|
||||
upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
|
||||
if (!in) return 0;
|
||||
|
|
@ -8105,6 +8092,25 @@ upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown2(
|
|||
: kUpb_DeleteUnknown_DeletedLast;
|
||||
}
|
||||
|
||||
upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown(
|
||||
struct upb_Message* msg, upb_StringView* data, uintptr_t* iter,
|
||||
struct upb_Arena* arena) {
|
||||
upb_MessageUnknown unknown;
|
||||
unknown.type = kUpb_MessageUnknownType_StringView;
|
||||
unknown.value.bytes = *data;
|
||||
|
||||
upb_Message_DeleteUnknownStatus res =
|
||||
upb_Message_DeleteUnknown2(msg, &unknown, iter, arena);
|
||||
UPB_ASSERT(unknown.type == kUpb_MessageUnknownType_StringView);
|
||||
if (res == kUpb_DeleteUnknown_IterUpdated ||
|
||||
res == kUpb_DeleteUnknown_DeletedLast) {
|
||||
// the unknown data remains the same on the result of
|
||||
// kUpb_DeleteUnknown_AllocFail.
|
||||
*data = unknown.value.bytes;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
|
@ -9040,12 +9046,21 @@ upb_Extension* UPB_PRIVATE(_upb_Message_GetOrCreateExtensionWithTag)(
|
|||
struct upb_Message* msg, const upb_MiniTableExtension* e, upb_Arena* a,
|
||||
upb_TaggedAuxType tag) {
|
||||
UPB_ASSERT(!upb_Message_IsFrozen(msg));
|
||||
upb_Extension* ext = (upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e);
|
||||
if (ext) return ext;
|
||||
|
||||
// For Canonical Extensions, we check whether the extension has already been
|
||||
// set. If we find an extension with the same pointer and tag, we reuse it to
|
||||
// prevent duplicate entries for the same extension.
|
||||
//
|
||||
// For Non-Canonical Extensions, we do NOT reuse them, matching the behavior
|
||||
// of adding a unknown StringView (through `_upb_Message_AddUnknown`) which
|
||||
// accumulates.
|
||||
if (tag == kUpb_TaggedAuxType_CanonicalExtension) {
|
||||
upb_Extension* ext =
|
||||
(upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e);
|
||||
if (ext) return ext;
|
||||
}
|
||||
if (!UPB_PRIVATE(_upb_Message_ReserveSlot)(msg, a)) return NULL;
|
||||
upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
|
||||
ext = upb_Arena_Malloc(a, sizeof(upb_Extension));
|
||||
upb_Extension* ext = upb_Arena_Malloc(a, sizeof(upb_Extension));
|
||||
if (!ext) return NULL;
|
||||
memset(ext, 0, sizeof(upb_Extension));
|
||||
ext->ext = e;
|
||||
|
|
@ -10135,6 +10150,7 @@ done:
|
|||
#endif
|
||||
|
||||
upb_MiniTable* ret = upb_Arena_Malloc(decoder->arena, mt_size);
|
||||
upb_MdDecoder_CheckOutOfMemory(&decoder->base, ret);
|
||||
memcpy(ret, &decoder->table, sizeof(*ret));
|
||||
|
||||
#if UPB_FASTTABLE
|
||||
|
|
@ -17803,6 +17819,49 @@ const char* upb_EncodeStatus_String(upb_EncodeStatus status) {
|
|||
}
|
||||
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
// Must be last.
|
||||
|
||||
static upb_EncodeStatus upb_DoEncodeExtension(upb_encstate* encoder, char* ptr,
|
||||
const struct upb_Extension* ext,
|
||||
bool is_message_set,
|
||||
upb_StringView* view,
|
||||
int encode_options) {
|
||||
if (UPB_SETJMP(*encoder->err) == 0) {
|
||||
char* buf = ptr;
|
||||
size_t size = 0;
|
||||
UPB_PRIVATE(_upb_Encode_Extension)(encoder, ext->ext, ext->data,
|
||||
is_message_set, &buf, &size,
|
||||
encode_options);
|
||||
view->data = buf;
|
||||
view->size = size;
|
||||
} else {
|
||||
UPB_ASSERT(encoder->status != kUpb_EncodeStatus_Ok);
|
||||
upb_BackAlloc_Abort(&encoder->alloc);
|
||||
view->data = NULL;
|
||||
view->size = 0;
|
||||
}
|
||||
UPB_PRIVATE(_upb_encstate_destroy)(encoder);
|
||||
return encoder->status;
|
||||
}
|
||||
|
||||
upb_EncodeStatus upb_EncodeExtension(const struct upb_Extension* ext,
|
||||
struct upb_Arena* arena,
|
||||
upb_StringView* view, int encode_options) {
|
||||
const upb_MiniTable* extendee = upb_MiniTableExtension_Extendee(ext->ext);
|
||||
bool is_message_set =
|
||||
extendee != NULL && upb_MiniTable_IsMessageSet(extendee);
|
||||
upb_encstate e;
|
||||
jmp_buf err;
|
||||
char* ptr = UPB_PRIVATE(_upb_encstate_init)(&e, &err, arena);
|
||||
return upb_DoEncodeExtension(&e, ptr, ext, is_message_set, view,
|
||||
encode_options);
|
||||
}
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
|
@ -18489,9 +18548,12 @@ static char* encode_map(char* ptr, upb_encstate* e, const upb_Message* msg,
|
|||
|
||||
if (e->options & kUpb_EncodeOption_Deterministic) {
|
||||
_upb_sortedmap sorted;
|
||||
_upb_mapsorter_pushmap(
|
||||
&e->sorter, layout->UPB_PRIVATE(fields)[0].UPB_PRIVATE(descriptortype),
|
||||
map, &sorted);
|
||||
if (!_upb_mapsorter_pushmap(
|
||||
&e->sorter,
|
||||
layout->UPB_PRIVATE(fields)[0].UPB_PRIVATE(descriptortype), map,
|
||||
&sorted)) {
|
||||
encode_err(e, kUpb_EncodeStatus_OutOfMemory);
|
||||
}
|
||||
upb_MapEntry ent;
|
||||
while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) {
|
||||
ptr = encode_mapentry(ptr, e, upb_MiniTableField_Number(f), layout, &ent);
|
||||
|
|
@ -18627,7 +18689,7 @@ static char* encode_exts(char* ptr, upb_encstate* e, const upb_MiniTable* m,
|
|||
if (e->options & kUpb_EncodeOption_Deterministic) {
|
||||
_upb_sortedmap sorted;
|
||||
if (!_upb_mapsorter_pushexts(&e->sorter, in, &sorted)) {
|
||||
// TODO: b/378744096 - handle alloc failure
|
||||
encode_err(e, kUpb_EncodeStatus_OutOfMemory);
|
||||
}
|
||||
const upb_Extension* ext;
|
||||
while (_upb_sortedmap_nextext(&e->sorter, &sorted, &ext)) {
|
||||
|
|
|
|||
|
|
@ -5711,139 +5711,6 @@ UPB_API_INLINE bool upb_Map_IsFrozen(const upb_Map* map);
|
|||
#include <stdint.h>
|
||||
|
||||
|
||||
#ifndef UPB_MESSAGE_UNKNOWN_FIELDS_H_
|
||||
#define UPB_MESSAGE_UNKNOWN_FIELDS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// Must be last.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct upb_Extension;
|
||||
|
||||
typedef enum {
|
||||
kUpb_MessageUnknownType_StringView,
|
||||
kUpb_MessageUnknownType_NonCanonicalExtension,
|
||||
} upb_MessageUnknownType;
|
||||
|
||||
// Represents an unknown field in a message, whether it's in a serialized
|
||||
// (upb_StringView) or parsed non-canonical extension (upb_Extension*) format.
|
||||
typedef struct upb_MessageUnknown {
|
||||
uint8_t type;
|
||||
union {
|
||||
upb_StringView bytes;
|
||||
const upb_Extension* extension;
|
||||
} value;
|
||||
} upb_MessageUnknown;
|
||||
|
||||
// Support iteration over unknown (upb_MessageUnknown*), including unknown
|
||||
// upb_StringView and non-canonical extensions (upb_Extension*).
|
||||
UPB_INLINE bool upb_Message_NextUnknown2(const struct upb_Message* msg,
|
||||
struct upb_MessageUnknown* data,
|
||||
uintptr_t* iter) {
|
||||
const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
|
||||
size_t i = *iter;
|
||||
if (in) {
|
||||
while (i < in->size) {
|
||||
upb_TaggedAuxPtr tagged_ptr = in->aux_data[i++];
|
||||
if (upb_TaggedAuxPtr_IsUnknownStringView(tagged_ptr)) {
|
||||
data->type = kUpb_MessageUnknownType_StringView;
|
||||
data->value.bytes = *upb_TaggedPtrAux_StringViewRepr(tagged_ptr);
|
||||
*iter = i;
|
||||
return true;
|
||||
} else if (upb_TaggedAuxPtr_IsNonCanonicalExtension(tagged_ptr)) {
|
||||
data->type = kUpb_MessageUnknownType_NonCanonicalExtension;
|
||||
data->value.extension =
|
||||
upb_TaggedAuxPtr_NonCanonicalExtension(tagged_ptr);
|
||||
*iter = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
data->type = kUpb_MessageUnknownType_StringView;
|
||||
data->value.bytes.size = 0;
|
||||
data->value.bytes.data = NULL;
|
||||
*iter = i;
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
kUpb_FindUnknown_Ok,
|
||||
kUpb_FindUnknown_NotPresent,
|
||||
kUpb_FindUnknown_ParseError,
|
||||
} upb_FindUnknown_Status;
|
||||
|
||||
typedef struct {
|
||||
upb_FindUnknown_Status status;
|
||||
struct upb_MessageUnknown unknown;
|
||||
uintptr_t iter;
|
||||
} upb_FindUnknownRet2;
|
||||
|
||||
// Finds first occurrence of unknown data (upb_MessageUnknown) by tag id in
|
||||
// message, including unknown upb_StringView and non-canonical extensions
|
||||
// (upb_Extension*).
|
||||
//
|
||||
// If multiple matching entries exist for the same field number (e.g. both a
|
||||
// raw unknown upb_StringView and a non-canonical extension), this function
|
||||
// returns the one encountered first in internal iteration order (which follows
|
||||
// the order they were added or parsed).
|
||||
//
|
||||
// A depth_limit of zero means to just use the upb default depth limit.
|
||||
upb_FindUnknownRet2 upb_Message_FindUnknown2(const struct upb_Message* msg,
|
||||
uint32_t field_number,
|
||||
int depth_limit);
|
||||
|
||||
typedef enum {
|
||||
kUpb_DeleteUnknown_DeletedLast,
|
||||
kUpb_DeleteUnknown_IterUpdated,
|
||||
kUpb_DeleteUnknown_AllocFail,
|
||||
} upb_Message_DeleteUnknownStatus;
|
||||
|
||||
// Removes a segment of unknown data from the message, advancing to the next
|
||||
// segment. Returns false if the removed segment was at the end of the last
|
||||
// chunk.
|
||||
//
|
||||
// This must be done while iterating:
|
||||
//
|
||||
// uintptr_t iter = kUpb_Message_UnknownBegin;
|
||||
// upb_MessageUnknown data;
|
||||
// // Iterate chunks
|
||||
// while (upb_Message_NextUnknown2(msg, &data, &iter)) {
|
||||
// // Iterate within a chunk, deleting ranges
|
||||
// while (ShouldDeleteSubSegment(&data)) {
|
||||
// // Data now points to the region to be deleted
|
||||
// switch (upb_Message_DeleteUnknown2(msg, &data, &iter)) {
|
||||
// case kUpb_DeleteUnknown_DeletedLast: return ok;
|
||||
// case kUpb_DeleteUnknown_IterUpdated: break;
|
||||
// // If DeleteUnknown returned kUpb_DeleteUnknown_IterUpdated,
|
||||
// // then data now points to the remaining unknown fields after the
|
||||
// // region that was just deleted.
|
||||
// case kUpb_Message_DeleteUnknown_AllocFail: return err;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// The range given in `data` must be contained inside the most recently
|
||||
// returned region.
|
||||
//
|
||||
// Support deletion of unknown (upb_MessageUnknown*), including unknown
|
||||
// upb_StringView and non-canonical extensions (upb_Extension*).
|
||||
UPB_NODISCARD upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown2(
|
||||
struct upb_Message* msg, struct upb_MessageUnknown* data, uintptr_t* iter,
|
||||
struct upb_Arena* arena);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* UPB_MESSAGE_UNKNOWN_FIELDS_H_ */
|
||||
|
||||
// Must be last.
|
||||
|
||||
typedef struct upb_Message upb_Message;
|
||||
|
|
@ -5889,39 +5756,6 @@ UPB_INLINE bool upb_Message_HasUnknown(const upb_Message* msg) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Removes a segment of unknown data from the message, advancing to the next
|
||||
// segment. Returns false if the removed segment was at the end of the last
|
||||
// chunk.
|
||||
//
|
||||
// This must be done while iterating:
|
||||
//
|
||||
// uintptr_t iter = kUpb_Message_UnknownBegin;
|
||||
// upb_StringView data;
|
||||
// // Iterate chunks
|
||||
// while (upb_Message_NextUnknown(msg, &data, &iter)) {
|
||||
// // Iterate within a chunk, deleting ranges
|
||||
// while (ShouldDeleteSubSegment(&data)) {
|
||||
// // Data now points to the region to be deleted
|
||||
// switch (upb_Message_DeleteUnknown(msg, &data, &iter)) {
|
||||
// case kUpb_Message_DeleteUnknown_DeletedLast: return ok;
|
||||
// case kUpb_Message_DeleteUnknown_IterUpdated: break;
|
||||
// // If DeleteUnknown returned kUpb_Message_DeleteUnknown_IterUpdated,
|
||||
// // then data now points to the remaining unknown fields after the
|
||||
// // region that was just deleted.
|
||||
// case kUpb_Message_DeleteUnknown_AllocFail: return err;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// The range given in `data` must be contained inside the most recently
|
||||
// returned region.
|
||||
//
|
||||
// TODO: b/510055656 - Legacy API that works with messages that only have
|
||||
// unknown data in upb_StringView format. Use `upb_Message_DeleteUnknown2` for
|
||||
// messages that may have non-canonical extensions.
|
||||
UPB_NODISCARD upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown(
|
||||
upb_Message* msg, upb_StringView* data, uintptr_t* iter, upb_Arena* arena);
|
||||
|
||||
// Returns the number of extensions present in this message.
|
||||
size_t upb_Message_ExtensionCount(const upb_Message* msg);
|
||||
|
||||
|
|
@ -16604,6 +16438,170 @@ bool _upb_mapsorter_pushexts(_upb_mapsorter* s, const upb_Message_Internal* in,
|
|||
|
||||
#endif /* UPB_MESSAGE_INTERNAL_MAP_SORTER_H_ */
|
||||
|
||||
#ifndef UPB_MESSAGE_UNKNOWN_FIELDS_H_
|
||||
#define UPB_MESSAGE_UNKNOWN_FIELDS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// Must be last.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
kUpb_MessageUnknownType_StringView,
|
||||
kUpb_MessageUnknownType_NonCanonicalExtension,
|
||||
} upb_MessageUnknownType;
|
||||
|
||||
// Represents an unknown field in a message, whether it's in a serialized
|
||||
// (upb_StringView) or parsed non-canonical extension (upb_Extension*) format.
|
||||
typedef struct upb_MessageUnknown {
|
||||
uint8_t type;
|
||||
union {
|
||||
upb_StringView bytes;
|
||||
const upb_Extension* extension;
|
||||
} value;
|
||||
} upb_MessageUnknown;
|
||||
|
||||
// Support iteration over unknown (upb_MessageUnknown*), including unknown
|
||||
// upb_StringView and non-canonical extensions (upb_Extension*).
|
||||
UPB_INLINE bool upb_Message_NextUnknown2(const struct upb_Message* msg,
|
||||
struct upb_MessageUnknown* data,
|
||||
uintptr_t* iter) {
|
||||
const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
|
||||
size_t i = *iter;
|
||||
if (in) {
|
||||
while (i < in->size) {
|
||||
upb_TaggedAuxPtr tagged_ptr = in->aux_data[i++];
|
||||
if (upb_TaggedAuxPtr_IsUnknownStringView(tagged_ptr)) {
|
||||
data->type = kUpb_MessageUnknownType_StringView;
|
||||
data->value.bytes = *upb_TaggedPtrAux_StringViewRepr(tagged_ptr);
|
||||
*iter = i;
|
||||
return true;
|
||||
} else if (upb_TaggedAuxPtr_IsNonCanonicalExtension(tagged_ptr)) {
|
||||
data->type = kUpb_MessageUnknownType_NonCanonicalExtension;
|
||||
data->value.extension =
|
||||
upb_TaggedAuxPtr_NonCanonicalExtension(tagged_ptr);
|
||||
*iter = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
data->type = kUpb_MessageUnknownType_StringView;
|
||||
data->value.bytes.size = 0;
|
||||
data->value.bytes.data = NULL;
|
||||
*iter = i;
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
kUpb_FindUnknown_Ok,
|
||||
kUpb_FindUnknown_NotPresent,
|
||||
kUpb_FindUnknown_ParseError,
|
||||
} upb_FindUnknown_Status;
|
||||
|
||||
typedef struct {
|
||||
upb_FindUnknown_Status status;
|
||||
struct upb_MessageUnknown unknown;
|
||||
uintptr_t iter;
|
||||
} upb_FindUnknownRet2;
|
||||
|
||||
// Finds first occurrence of unknown data (upb_MessageUnknown) by tag id in
|
||||
// message, including unknown upb_StringView and non-canonical extensions
|
||||
// (upb_Extension*).
|
||||
//
|
||||
// If multiple matching entries exist for the same field number (e.g. both a
|
||||
// raw unknown upb_StringView and a non-canonical extension), this function
|
||||
// returns the one encountered first in internal iteration order (which follows
|
||||
// the order they were added or parsed).
|
||||
//
|
||||
// A depth_limit of zero means to just use the upb default depth limit.
|
||||
upb_FindUnknownRet2 upb_Message_FindUnknown2(const struct upb_Message* msg,
|
||||
uint32_t field_number,
|
||||
int depth_limit);
|
||||
|
||||
typedef enum {
|
||||
kUpb_DeleteUnknown_DeletedLast,
|
||||
kUpb_DeleteUnknown_IterUpdated,
|
||||
kUpb_DeleteUnknown_AllocFail,
|
||||
} upb_Message_DeleteUnknownStatus;
|
||||
|
||||
// Removes a segment of unknown data from the message, advancing to the next
|
||||
// segment. Returns false if the removed segment was at the end of the last
|
||||
// chunk.
|
||||
//
|
||||
// This must be done while iterating:
|
||||
//
|
||||
// uintptr_t iter = kUpb_Message_UnknownBegin;
|
||||
// upb_StringView data;
|
||||
// // Iterate chunks
|
||||
// while (upb_Message_NextUnknown(msg, &data, &iter)) {
|
||||
// // Iterate within a chunk, deleting ranges
|
||||
// while (ShouldDeleteSubSegment(&data)) {
|
||||
// // Data now points to the region to be deleted
|
||||
// switch (upb_Message_DeleteUnknown(msg, &data, &iter)) {
|
||||
// case kUpb_DeleteUnknown_DeletedLast: return ok;
|
||||
// case kUpb_DeleteUnknown_IterUpdated: break;
|
||||
// // If DeleteUnknown returned kUpb_DeleteUnknown_IterUpdated,
|
||||
// // then data now points to the remaining unknown fields after the
|
||||
// // region that was just deleted.
|
||||
// case kUpb_DeleteUnknown_AllocFail: return err;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// The range given in `data` must be contained inside the most recently
|
||||
// returned region.
|
||||
// TODO: b/510055656 - Legacy API that works with messages that only have
|
||||
// unknown data in upb_StringView format. Use `upb_Message_DeleteUnknown2` for
|
||||
// messages that may have non-canonical extensions.
|
||||
UPB_NODISCARD upb_Message_DeleteUnknownStatus
|
||||
upb_Message_DeleteUnknown(struct upb_Message* msg, upb_StringView* data,
|
||||
uintptr_t* iter, struct upb_Arena* arena);
|
||||
|
||||
// Removes a segment of unknown data from the message, advancing to the next
|
||||
// segment. Returns false if the removed segment was at the end of the last
|
||||
// chunk.
|
||||
//
|
||||
// This must be done while iterating:
|
||||
//
|
||||
// uintptr_t iter = kUpb_Message_UnknownBegin;
|
||||
// upb_MessageUnknown data;
|
||||
// // Iterate chunks
|
||||
// while (upb_Message_NextUnknown2(msg, &data, &iter)) {
|
||||
// // Iterate within a chunk, deleting ranges
|
||||
// while (ShouldDeleteSubSegment(&data)) {
|
||||
// // Data now points to the region to be deleted
|
||||
// switch (upb_Message_DeleteUnknown2(msg, &data, &iter)) {
|
||||
// case kUpb_DeleteUnknown_DeletedLast: return ok;
|
||||
// case kUpb_DeleteUnknown_IterUpdated: break;
|
||||
// // If DeleteUnknown returned kUpb_DeleteUnknown_IterUpdated,
|
||||
// // then data now points to the remaining unknown fields after the
|
||||
// // region that was just deleted.
|
||||
// case kUpb_DeleteUnknown_AllocFail: return err;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// The range given in `data` must be contained inside the most recently
|
||||
// returned region.
|
||||
//
|
||||
// Support deletion of unknown (upb_MessageUnknown*), including unknown
|
||||
// upb_StringView and non-canonical extensions (upb_Extension*).
|
||||
UPB_NODISCARD upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown2(
|
||||
struct upb_Message* msg, struct upb_MessageUnknown* data, uintptr_t* iter,
|
||||
struct upb_Arena* arena);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* UPB_MESSAGE_UNKNOWN_FIELDS_H_ */
|
||||
|
||||
#ifndef UPB_WIRE_EPS_COPY_INPUT_STREAM_H_
|
||||
#define UPB_WIRE_EPS_COPY_INPUT_STREAM_H_
|
||||
|
||||
|
|
@ -19300,6 +19298,33 @@ void _upb_Decoder_AddEnumValueToUnknown(upb_Decoder* d, upb_Message* msg,
|
|||
|
||||
|
||||
#endif /* UPB_WIRE_INTERNAL_DECODER_H_ */
|
||||
|
||||
#ifndef UPB_WIRE_ENCODE_EXTENSION_H_
|
||||
#define UPB_WIRE_ENCODE_EXTENSION_H_
|
||||
|
||||
|
||||
// Must be last.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct upb_Extension;
|
||||
|
||||
// Encodes an extension (`upb_Extension*`) to bytes.
|
||||
//
|
||||
// This can be used to encode an extension into the provided arena.
|
||||
// Returns `kUpb_EncodeStatus_Ok` on success.
|
||||
UPB_NODISCARD upb_EncodeStatus
|
||||
upb_EncodeExtension(const struct upb_Extension* ext, struct upb_Arena* arena,
|
||||
upb_StringView* view, int encode_options);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* UPB_WIRE_ENCODE_EXTENSION_H_ */
|
||||
#ifndef GOOGLE_UPB_UPB_WIRE_WRITER_H__
|
||||
#define GOOGLE_UPB_UPB_WIRE_WRITER_H__
|
||||
|
||||
|
|
|
|||
|
|
@ -104,4 +104,57 @@ class GCTest < Test::Unit::TestCase
|
|||
GC.stress = old_gc
|
||||
puts "passed"
|
||||
end
|
||||
|
||||
# Regression test: the map key must be copied into the arena, not aliased.
|
||||
#
|
||||
# Convert_RubyToUpb returns a *temporary* String for a key that is a Symbol or
|
||||
# is not already tagged UTF-8. Converting the value afterwards allocates, which
|
||||
# can trigger GC and free that temporary before upb_Map_Set copies the key --
|
||||
# leaving a silently corrupted key holding unrelated heap bytes.
|
||||
def assert_map_keys_survive_gc(&builder)
|
||||
old_gc = GC.stress
|
||||
GC.stress = true
|
||||
begin
|
||||
100.times do
|
||||
# Non-UTF-8 key and value: the key conversion allocates a temporary, and
|
||||
# the value conversion allocates again, opening the window.
|
||||
key = ("K" * 5000).dup.force_encoding("ISO-8859-1") +
|
||||
"\xE9".dup.force_encoding("ISO-8859-1")
|
||||
value = ("V" * 5000).dup.force_encoding("ISO-8859-1") +
|
||||
"\xE9".dup.force_encoding("ISO-8859-1")
|
||||
assert_equal [key.encode("UTF-8")], builder.call(key, value).keys
|
||||
end
|
||||
ensure
|
||||
GC.stress = old_gc
|
||||
end
|
||||
end
|
||||
|
||||
def test_map_string_key_not_corrupted_by_gc
|
||||
assert_map_keys_survive_gc do |key, value|
|
||||
map = Google::Protobuf::Map.new(:string, :string)
|
||||
map[key] = value
|
||||
map
|
||||
end
|
||||
end
|
||||
|
||||
def test_map_symbol_key_not_corrupted_by_gc
|
||||
old_gc = GC.stress
|
||||
GC.stress = true
|
||||
begin
|
||||
100.times do
|
||||
map = Google::Protobuf::Map.new(:string, :string)
|
||||
map[:some_symbol_key] = :some_symbol_value
|
||||
assert_equal ["some_symbol_key"], map.keys
|
||||
end
|
||||
ensure
|
||||
GC.stress = old_gc
|
||||
end
|
||||
end
|
||||
|
||||
def test_map_field_kwarg_key_not_corrupted_by_gc
|
||||
assert_map_keys_survive_gc do |key, value|
|
||||
A::B::C::TestMessage.new(:map_string_string => { key => value })
|
||||
.map_string_string
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
43
rust/BUILD
43
rust/BUILD
|
|
@ -38,6 +38,18 @@ rust_library(
|
|||
"//conditions:default": ["--cfg=cpp_kernel"],
|
||||
}),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [":protobuf_lite"],
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "protobuf_lite",
|
||||
srcs = ["protobuf_lite.rs"],
|
||||
edition = "2024",
|
||||
rustc_flags = select({
|
||||
":use_upb_kernel": ["--cfg=upb_kernel"],
|
||||
"//conditions:default": ["--cfg=cpp_kernel"],
|
||||
}),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = select({
|
||||
":use_upb_kernel": [":protobuf_upb"],
|
||||
"//conditions:default": [":protobuf_cpp"],
|
||||
|
|
@ -83,6 +95,7 @@ ALL_RUST_SRCS = PROTOBUF_SHARED + [
|
|||
"gtest_matchers.rs",
|
||||
"gtest_matchers_impl.rs",
|
||||
"protobuf.rs",
|
||||
"protobuf_lite.rs",
|
||||
"upb_kernel/conversions.rs",
|
||||
"upb_kernel/extension.rs",
|
||||
"upb_kernel/interop.rs",
|
||||
|
|
@ -146,15 +159,26 @@ rust_test(
|
|||
# This provides an identical set of re-exports as `:protobuf` with `:use_upb_kernel` active.
|
||||
# This is only used for tests shared between runtimes.
|
||||
rust_library(
|
||||
name = "protobuf_upb_export",
|
||||
name = "protobuf_upb_lite_export",
|
||||
testonly = True,
|
||||
srcs = ["protobuf.rs"],
|
||||
srcs = ["protobuf_lite.rs"],
|
||||
edition = "2024",
|
||||
rustc_flags = ["--cfg=upb_kernel"],
|
||||
visibility = [":protobuf_internal"],
|
||||
deps = [":protobuf_upb"],
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "protobuf_upb_export",
|
||||
testonly = True,
|
||||
srcs = ["protobuf.rs"],
|
||||
aliases = {"//rust:protobuf_upb_lite_export": "protobuf_lite"},
|
||||
edition = "2024",
|
||||
rustc_flags = ["--cfg=upb_kernel"],
|
||||
visibility = [":protobuf_internal"],
|
||||
deps = [":protobuf_upb_lite_export"],
|
||||
)
|
||||
|
||||
# The Rust Protobuf runtime using the cpp kernel.
|
||||
#
|
||||
# `rust_cpp_proto_library` implicitly depends on this target. This target cannot depend on
|
||||
|
|
@ -204,15 +228,26 @@ rust_test(
|
|||
# This provides an identical set of re-exports as `:protobuf` with `:use_upb_kernel` inactive.
|
||||
# This is only used for tests shared between runtimes.
|
||||
rust_library(
|
||||
name = "protobuf_cpp_export",
|
||||
name = "protobuf_cpp_lite_export",
|
||||
testonly = True,
|
||||
srcs = ["protobuf.rs"],
|
||||
srcs = ["protobuf_lite.rs"],
|
||||
edition = "2024",
|
||||
rustc_flags = ["--cfg=cpp_kernel"],
|
||||
visibility = [":protobuf_internal"],
|
||||
deps = [":protobuf_cpp"],
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "protobuf_cpp_export",
|
||||
testonly = True,
|
||||
srcs = ["protobuf.rs"],
|
||||
aliases = {"//rust:protobuf_cpp_lite_export": "protobuf_lite"},
|
||||
edition = "2024",
|
||||
rustc_flags = ["--cfg=cpp_kernel"],
|
||||
visibility = [":protobuf_internal"],
|
||||
deps = [":protobuf_cpp_lite_export"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "cpp_api",
|
||||
srcs = [
|
||||
|
|
|
|||
|
|
@ -1,34 +1,13 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google LLC. All rights reserved.
|
||||
// Copyright 2024 Google LLC. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
//! Rust Protobuf Runtime
|
||||
//! Rust Protobuf Full Runtime
|
||||
//!
|
||||
//! This file exists as the public entry point for the Rust Protobuf runtime. It
|
||||
//! is a thin re-export of the `shared.rs` file but is needed for two reasons:
|
||||
//! - To create a single `protobuf` crate name for either cpp and upb kernels
|
||||
//! from user code (toggled at compile time).
|
||||
//! - Blocks the __internal module from being re-exported to application code,
|
||||
//! unless they use one of our visibility-restricted targets (gencode does
|
||||
//! have access to them).
|
||||
//! This crate re-exports the `protobuf` lite runtime and (in the future) adds reflection
|
||||
//! traits and heavy APIs (like text formatting) that are banned in `lite` mode.
|
||||
|
||||
#[cfg(cpp_kernel)]
|
||||
use protobuf_cpp as kernel;
|
||||
|
||||
#[cfg(upb_kernel)]
|
||||
use protobuf_upb as kernel;
|
||||
|
||||
/// Block these two mods from being re-exported by the `pub use`
|
||||
/// below (glob use automatically only adds things that aren't otherwise
|
||||
/// defined).
|
||||
///
|
||||
/// By creating a const instead of an empty mod it is easier to have a test
|
||||
/// that confirms this targeted 'blocking' is working as intended.
|
||||
#[doc(hidden)]
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const __internal: () = ();
|
||||
|
||||
pub use kernel::*;
|
||||
pub use protobuf_lite::*;
|
||||
|
|
|
|||
34
rust/protobuf_lite.rs
Normal file
34
rust/protobuf_lite.rs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2026 Google LLC. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
//! Rust Protobuf Runtime
|
||||
//!
|
||||
//! This file exists as the public entry point for the Rust Protobuf runtime. It
|
||||
//! is a thin re-export of the `shared.rs` file but is needed for two reasons:
|
||||
//! - To create a single `protobuf` crate name for either cpp and upb kernels
|
||||
//! from user code (toggled at compile time).
|
||||
//! - Blocks the __internal module from being re-exported to application code,
|
||||
//! unless they use one of our visibility-restricted targets (gencode does
|
||||
//! have access to them).
|
||||
|
||||
#[cfg(cpp_kernel)]
|
||||
use protobuf_cpp as kernel;
|
||||
|
||||
#[cfg(upb_kernel)]
|
||||
use protobuf_upb as kernel;
|
||||
|
||||
/// Block these two mods from being re-exported by the `pub use`
|
||||
/// below (glob use automatically only adds things that aren't otherwise
|
||||
/// defined).
|
||||
///
|
||||
/// By creating a const instead of an empty mod it is easier to have a test
|
||||
/// that confirms this targeted 'blocking' is working as intended.
|
||||
#[doc(hidden)]
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const __internal: () = ();
|
||||
|
||||
pub use kernel::*;
|
||||
|
|
@ -74,6 +74,7 @@ set(libprotobuf_srcs
|
|||
${protobuf_SOURCE_DIR}/src/google/protobuf/message_lite.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/micro_string.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/naming_style.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/offset_ptr.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/option_interpreter.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/parse_context.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/port.cc
|
||||
|
|
@ -188,6 +189,7 @@ set(libprotobuf_hdrs
|
|||
${protobuf_SOURCE_DIR}/src/google/protobuf/metadata_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/micro_string.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/naming_style.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/offset_ptr.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/option_interpreter.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/os_macros_restore.inc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/os_macros_undef.inc
|
||||
|
|
@ -259,6 +261,7 @@ set(libprotobuf_lite_srcs
|
|||
${protobuf_SOURCE_DIR}/src/google/protobuf/map.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/message_lite.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/micro_string.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/offset_ptr.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/parse_context.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/port.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/raw_ptr.cc
|
||||
|
|
@ -307,6 +310,7 @@ set(libprotobuf_lite_hdrs
|
|||
${protobuf_SOURCE_DIR}/src/google/protobuf/message_traits.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/metadata_lite.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/micro_string.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/offset_ptr.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/os_macros_restore.inc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/os_macros_undef.inc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/parse_context.h
|
||||
|
|
@ -349,6 +353,7 @@ set(libprotoc_public_srcs
|
|||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/names.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/names.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/retention.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/subprocess.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/versions.cc
|
||||
|
|
@ -379,6 +384,7 @@ set(libprotoc_public_hdrs
|
|||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/php/names.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/names.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/retention.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/scc.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/subprocess.h
|
||||
|
|
@ -493,6 +499,7 @@ set(libprotoc_srcs
|
|||
${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/names.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/pyi_generator.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/retention.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/ruby/rbs_generator.cc
|
||||
|
|
@ -644,6 +651,7 @@ set(libprotoc_hdrs
|
|||
${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/names.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/pyi_generator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/retention.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/ruby/rbs_generator.h
|
||||
|
|
@ -744,6 +752,7 @@ set(libupb_srcs
|
|||
${protobuf_SOURCE_DIR}/upb/wire/decode.c
|
||||
${protobuf_SOURCE_DIR}/upb/wire/decode_fast/select.c
|
||||
${protobuf_SOURCE_DIR}/upb/wire/encode.c
|
||||
${protobuf_SOURCE_DIR}/upb/wire/encode_extension.c
|
||||
${protobuf_SOURCE_DIR}/upb/wire/eps_copy_input_stream.c
|
||||
${protobuf_SOURCE_DIR}/upb/wire/internal/back_alloc.c
|
||||
${protobuf_SOURCE_DIR}/upb/wire/internal/decoder.c
|
||||
|
|
@ -874,6 +883,7 @@ set(libupb_hdrs
|
|||
${protobuf_SOURCE_DIR}/upb/wire/decode_fast/data.h
|
||||
${protobuf_SOURCE_DIR}/upb/wire/decode_fast/select.h
|
||||
${protobuf_SOURCE_DIR}/upb/wire/encode.h
|
||||
${protobuf_SOURCE_DIR}/upb/wire/encode_extension.h
|
||||
${protobuf_SOURCE_DIR}/upb/wire/eps_copy_input_stream.h
|
||||
${protobuf_SOURCE_DIR}/upb/wire/internal/back_alloc.h
|
||||
${protobuf_SOURCE_DIR}/upb/wire/internal/constants.h
|
||||
|
|
@ -1291,6 +1301,7 @@ set(protobuf_test_files
|
|||
${protobuf_SOURCE_DIR}/src/google/protobuf/naming_style_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/no_field_presence_map_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/no_field_presence_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/offset_ptr_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/port_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/preserve_unknown_enum_test.cc
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/proto3_arena_lite_unittest.cc
|
||||
|
|
|
|||
|
|
@ -726,6 +726,7 @@ cc_library(
|
|||
"inlined_string_field.cc",
|
||||
"map.cc",
|
||||
"message_lite.cc",
|
||||
"offset_ptr.cc",
|
||||
"parse_context.cc",
|
||||
"raw_ptr.cc",
|
||||
"repeated_field.cc",
|
||||
|
|
@ -759,6 +760,7 @@ cc_library(
|
|||
"map_type_handler.h",
|
||||
"message_lite.h",
|
||||
"metadata_lite.h",
|
||||
"offset_ptr.h",
|
||||
"parse_context.h",
|
||||
"raw_ptr.h",
|
||||
"repeated_field.h",
|
||||
|
|
@ -988,6 +990,17 @@ cc_test(
|
|||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "offset_ptr_test",
|
||||
srcs = ["offset_ptr_test.cc"],
|
||||
deps = [
|
||||
":cc_test_protos",
|
||||
":protobuf_lite",
|
||||
"@googletest//:gtest",
|
||||
"@googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
# This target exposes the headers for the protobuf runtime, and additionally
|
||||
# depends on the C++ well-known types and some other miscellaneous utilities.
|
||||
# The purpose is to preserve compatibility with projects that do not yet comply
|
||||
|
|
|
|||
|
|
@ -211,7 +211,6 @@ void CordFieldGenerator::GenerateInlineAccessorDefinitions(
|
|||
p->Emit(R"cc(
|
||||
inline void $Msg$::set_$name$(const ::absl::Cord& value) {
|
||||
$WeakDescriptorSelfPin$;
|
||||
$PrepareSplitMessageForWrite$;
|
||||
_internal_set_$name_internal$(value);
|
||||
$annotate_set$;
|
||||
// @@protoc_insertion_point(field_set:$full_name$)
|
||||
|
|
@ -220,7 +219,6 @@ void CordFieldGenerator::GenerateInlineAccessorDefinitions(
|
|||
p->Emit(R"cc(
|
||||
inline void $Msg$::set_$name$(::absl::string_view value) {
|
||||
$WeakDescriptorSelfPin$;
|
||||
$PrepareSplitMessageForWrite$;
|
||||
$set_hasbit$;
|
||||
$field_$ = value;
|
||||
$annotate_set$;
|
||||
|
|
|
|||
|
|
@ -238,7 +238,6 @@ void Map::GenerateInlineAccessorDefinitions(io::Printer* p) const {
|
|||
)cc");
|
||||
p->Emit(R"cc(
|
||||
inline $Map$* $nonnull$ $Msg$::_internal_mutable_$name_internal$() {
|
||||
$PrepareSplitMessageForWrite$;
|
||||
$TsanDetectConcurrentMutation$;
|
||||
return $field_$.MutableMap();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3693,6 +3693,10 @@ MessageGenerator::NewOpRequirements MessageGenerator::GetNewOp() const {
|
|||
// We can't skip the ArenaDtor for these messages.
|
||||
op.needs_to_run_constructor = true;
|
||||
}
|
||||
if (descriptor_->extension_range_count() > 0) {
|
||||
// Extensions are not zero-initializable.
|
||||
op.needs_memcpy = true;
|
||||
}
|
||||
|
||||
for (const FieldDescriptor* field : internal::FieldRange(descriptor_)) {
|
||||
if (ShouldSplit(field, options_)) {
|
||||
|
|
|
|||
|
|
@ -49,11 +49,9 @@ struct MockZeroFieldsBase : public MockMessageBase {
|
|||
ABSL_CHECK_MESSAGE_SIZE(MockZeroFieldsBase, 24);
|
||||
|
||||
struct MockExtensionSet {
|
||||
int16_t capacity; // 4 bytes
|
||||
int16_t size; // 4 bytes
|
||||
void* data; // 8 bytes
|
||||
};
|
||||
ABSL_CHECK_MESSAGE_SIZE(MockExtensionSet, 16);
|
||||
ABSL_CHECK_MESSAGE_SIZE(MockExtensionSet, 8);
|
||||
|
||||
struct MockRepeatedPtrField {
|
||||
int current_size; // 4 bytes
|
||||
|
|
@ -95,12 +93,12 @@ TEST(GeneratedMessageTest, ReservedSize) {
|
|||
|
||||
TEST(GeneratedMessageTest, EmptyMessageWithExtensionsSize) {
|
||||
struct MockGenerated : public MockMessageBase { // 16 bytes
|
||||
MockExtensionSet extensions; // 24 bytes
|
||||
MockExtensionSet extensions; // 8 bytes
|
||||
int cached_size; // 4 bytes
|
||||
PROTOBUF_TSAN_DECLARE_MEMBER; // 0-4 bytes
|
||||
// + 0-4 bytes of padding
|
||||
};
|
||||
ABSL_CHECK_MESSAGE_SIZE(MockGenerated, 40);
|
||||
ABSL_CHECK_MESSAGE_SIZE(MockGenerated, 32);
|
||||
EXPECT_EQ(sizeof(proto2_unittest::TestEmptyMessageWithExtensions),
|
||||
sizeof(MockGenerated));
|
||||
}
|
||||
|
|
@ -288,7 +286,7 @@ TEST(GeneratedMessageTest, FieldOrderingsSize) {
|
|||
struct MockGenerated : public MockMessageBase { // 16 bytes
|
||||
int has_bits[1]; // 4 bytes
|
||||
int cached_size; // 4 bytes
|
||||
MockExtensionSet extensions; // 24 bytes
|
||||
MockExtensionSet extensions; // 8 bytes
|
||||
void* my_string; // 8 bytes
|
||||
void* optional_nested_message; // 8 bytes
|
||||
int64_t my_int; // 8 bytes
|
||||
|
|
@ -296,12 +294,12 @@ TEST(GeneratedMessageTest, FieldOrderingsSize) {
|
|||
PROTOBUF_TSAN_DECLARE_MEMBER; // 0-4 bytes
|
||||
// + 0-4 bytes padding
|
||||
};
|
||||
ABSL_CHECK_MESSAGE_SIZE(MockGenerated, 72);
|
||||
ABSL_CHECK_MESSAGE_SIZE(MockGenerated, 64);
|
||||
|
||||
struct MockGeneratedExperiments : public MockMessageBase { // 16 bytes
|
||||
int has_bits[1]; // 4 bytes
|
||||
int cached_size; // 4 bytes
|
||||
MockExtensionSet extensions; // 24 bytes
|
||||
MockExtensionSet extensions; // 8 bytes
|
||||
std::string my_string; // sizeof(std::string)
|
||||
MockLazy optional_nested_message; // lazy, see above.
|
||||
int64_t my_int; // 8 bytes
|
||||
|
|
@ -309,17 +307,17 @@ TEST(GeneratedMessageTest, FieldOrderingsSize) {
|
|||
PROTOBUF_TSAN_DECLARE_MEMBER; // 0-4 bytes
|
||||
// + 0-4 bytes padding
|
||||
};
|
||||
ABSL_CHECK_MESSAGE_SIZE(MockGeneratedExperiments, 80 + sizeof(MockLazy));
|
||||
ABSL_CHECK_MESSAGE_SIZE(MockGeneratedExperiments, 72 + sizeof(MockLazy));
|
||||
|
||||
struct MockGeneratedSplit : public MockMessageBase { // 16 bytes
|
||||
int has_bits[1]; // 4 bytes
|
||||
int cached_size; // 4 bytes
|
||||
MockExtensionSet extensions; // 24 bytes
|
||||
MockExtensionSet extensions; // 8 bytes
|
||||
void* split; // 8 bytes
|
||||
PROTOBUF_TSAN_DECLARE_MEMBER; // 0-4 bytes
|
||||
// + 0-4 bytes padding
|
||||
};
|
||||
ABSL_CHECK_MESSAGE_SIZE(MockGeneratedSplit, 48);
|
||||
ABSL_CHECK_MESSAGE_SIZE(MockGeneratedSplit, 40);
|
||||
|
||||
#ifndef PROTOBUF_FORCE_SPLIT
|
||||
// Make sure both or none are on for this test.
|
||||
|
|
|
|||
|
|
@ -40,9 +40,8 @@ namespace {
|
|||
using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
|
||||
|
||||
void SetEnumVariables(
|
||||
const FieldDescriptor* descriptor, int message_bit_index,
|
||||
int builder_bit_index, const FieldGeneratorInfo* info,
|
||||
ClassNameResolver* name_resolver,
|
||||
const FieldDescriptor* descriptor, int bit_index,
|
||||
const FieldGeneratorInfo* info, ClassNameResolver* name_resolver,
|
||||
absl::flat_hash_map<absl::string_view, std::string>* variables,
|
||||
Context* context) {
|
||||
SetCommonFieldVariables(descriptor, info, variables);
|
||||
|
|
@ -75,27 +74,26 @@ void SetEnumVariables(
|
|||
// For singular messages and builders, one bit is used for the hasField bit.
|
||||
// Note that these have a trailing ";".
|
||||
(*variables)["set_has_field_bit_to_local"] =
|
||||
GenerateSetBitToLocal(message_bit_index);
|
||||
(*variables)["is_field_present_message"] =
|
||||
GenerateGetBit(message_bit_index);
|
||||
GenerateSetBitToLocal(bit_index);
|
||||
(*variables)["is_field_present"] = GenerateGetBit(bit_index);
|
||||
} else {
|
||||
(*variables)["set_has_field_bit_to_local"] = "";
|
||||
variables->insert({"is_field_present_message",
|
||||
variables->insert({"is_field_present",
|
||||
absl::StrCat((*variables)["name"], "_ != ",
|
||||
(*variables)["default"], ".getNumber()")});
|
||||
}
|
||||
|
||||
// Always track the presence of a field explicitly in the builder, regardless
|
||||
// of syntax.
|
||||
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builder_bit_index);
|
||||
(*variables)["get_has_field_bit"] = GenerateGetBit(bit_index);
|
||||
(*variables)["get_has_field_bit_from_local"] =
|
||||
GenerateGetBitFromLocal(builder_bit_index);
|
||||
GenerateGetBitFromLocal(bit_index);
|
||||
|
||||
// Note that these have a trailing ";".
|
||||
(*variables)["set_has_field_bit_builder"] =
|
||||
absl::StrCat(GenerateSetBit(builder_bit_index), ";");
|
||||
(*variables)["clear_has_field_bit_builder"] =
|
||||
absl::StrCat(GenerateClearBit(builder_bit_index), ";");
|
||||
(*variables)["set_has_field_bit"] =
|
||||
absl::StrCat(GenerateSetBit(bit_index), ";");
|
||||
(*variables)["clear_has_field_bit"] =
|
||||
absl::StrCat(GenerateClearBit(bit_index), ";");
|
||||
|
||||
(*variables)["unknown"] =
|
||||
SupportUnknownEnumValue(descriptor)
|
||||
|
|
@ -108,21 +106,16 @@ void SetEnumVariables(
|
|||
// ===================================================================
|
||||
|
||||
ImmutableEnumFieldGenerator::ImmutableEnumFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int message_bit_index,
|
||||
int builder_bit_index, Context* context)
|
||||
: ImmutableFieldGenerator(descriptor, message_bit_index, builder_bit_index,
|
||||
context) {
|
||||
SetEnumVariables(descriptor, message_bit_index, builder_bit_index,
|
||||
const FieldDescriptor* descriptor, int bit_index, Context* context)
|
||||
: ImmutableFieldGenerator(descriptor, bit_index, context) {
|
||||
SetEnumVariables(descriptor, bit_index,
|
||||
context->GetFieldGeneratorInfo(descriptor), name_resolver_,
|
||||
&variables_, context);
|
||||
}
|
||||
|
||||
ImmutableEnumFieldGenerator::~ImmutableEnumFieldGenerator() = default;
|
||||
|
||||
int ImmutableEnumFieldGenerator::GetNumBitsForMessage() const {
|
||||
return HasHasbit(descriptor_) ? 1 : 0;
|
||||
}
|
||||
void ImmutableEnumFieldGenerator::GenerateInterfaceMembers(
|
||||
void ImmutableEnumFieldGenerator::GenerateInterfaceHasMethod(
|
||||
io::Printer* printer) const {
|
||||
if (descriptor_->has_presence()) {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
|
||||
|
|
@ -130,30 +123,48 @@ void ImmutableEnumFieldGenerator::GenerateInterfaceMembers(
|
|||
printer->Print(variables_,
|
||||
"$deprecation$boolean has$capitalized_name$();\n");
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableEnumFieldGenerator::GenerateInterfaceGetValueMethod(
|
||||
io::Printer* printer) const {
|
||||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$int get$capitalized_name$Value();\n");
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableEnumFieldGenerator::GenerateInterfaceGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n");
|
||||
}
|
||||
|
||||
void ImmutableEnumFieldGenerator::GenerateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_, "private int $name$_ = $default_number$;\n");
|
||||
PrintExtraFieldInfo(variables_, printer);
|
||||
void ImmutableEnumFieldGenerator::GenerateInterfaceMembers(
|
||||
io::Printer* printer) const {
|
||||
GenerateInterfaceHasMethod(printer);
|
||||
GenerateInterfaceGetValueMethod(printer);
|
||||
GenerateInterfaceGetMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutableEnumFieldGenerator::GenerateHasMethod(
|
||||
io::Printer* printer) const {
|
||||
if (descriptor_->has_presence()) {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"@java.lang.Override $deprecation$public boolean "
|
||||
"${$has$capitalized_name$$}$() {\n"
|
||||
" return $is_field_present_message$;\n"
|
||||
" return $is_field_present$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableEnumFieldGenerator::GenerateGetValueMethod(
|
||||
io::Printer* printer) const {
|
||||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
|
|
@ -164,6 +175,10 @@ void ImmutableEnumFieldGenerator::GenerateMembers(io::Printer* printer) const {
|
|||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableEnumFieldGenerator::GenerateGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
|
|
@ -175,19 +190,30 @@ void ImmutableEnumFieldGenerator::GenerateMembers(io::Printer* printer) const {
|
|||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
||||
io::Printer* printer) const {
|
||||
void ImmutableEnumFieldGenerator::GenerateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_, "private int $name$_ = $default_number$;\n");
|
||||
PrintExtraFieldInfo(variables_, printer);
|
||||
GenerateHasMethod(printer);
|
||||
GenerateGetValueMethod(printer);
|
||||
GenerateGetMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutableEnumFieldGenerator::GenerateBuilderHasMethod(
|
||||
io::Printer* printer) const {
|
||||
if (descriptor_->has_presence()) {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"@java.lang.Override $deprecation$public boolean "
|
||||
"${$has$capitalized_name$$}$() {\n"
|
||||
" return $get_has_field_bit_builder$;\n"
|
||||
" return $get_has_field_bit$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableEnumFieldGenerator::GenerateBuilderGetValueMethod(
|
||||
io::Printer* printer) const {
|
||||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
|
|
@ -197,6 +223,12 @@ void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
|||
" return $name$_;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableEnumFieldGenerator::GenerateBuilderSetValueMethod(
|
||||
io::Printer* printer) const {
|
||||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -204,12 +236,16 @@ void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
|||
"$deprecation$public Builder "
|
||||
"${$set$capitalized_name$Value$}$(int value) {\n"
|
||||
" $name$_ = value;\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" onChanged();\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableEnumFieldGenerator::GenerateBuilderGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
|
|
@ -219,6 +255,10 @@ void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
|||
" return result == null ? $unknown$ : result;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutableEnumFieldGenerator::GenerateBuilderSetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -226,19 +266,23 @@ void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
|||
"$deprecation$public Builder "
|
||||
"${$set$capitalized_name$$}$($type$ value) {\n"
|
||||
" $null_check$\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" $name$_ = value.getNumber();\n"
|
||||
" onChanged();\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void ImmutableEnumFieldGenerator::GenerateBuilderClearMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
|
||||
" $clear_has_field_bit_builder$\n"
|
||||
" $clear_has_field_bit$\n"
|
||||
" $name$_ = $default_number$;\n"
|
||||
" onChanged();\n"
|
||||
" return this;\n"
|
||||
|
|
@ -246,6 +290,17 @@ void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
|||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(variables_, "private int $name$_ = $default_number$;\n");
|
||||
GenerateBuilderHasMethod(printer);
|
||||
GenerateBuilderGetValueMethod(printer);
|
||||
GenerateBuilderSetValueMethod(printer);
|
||||
GenerateBuilderGetMethod(printer);
|
||||
GenerateBuilderSetMethod(printer);
|
||||
GenerateBuilderClearMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutableEnumFieldGenerator::GenerateFieldBuilderInitializationCode(
|
||||
io::Printer* printer) const {
|
||||
// noop for enums
|
||||
|
|
@ -286,7 +341,7 @@ void ImmutableEnumFieldGenerator::GenerateBuildingCode(
|
|||
printer->Print(variables_,
|
||||
"if ($get_has_field_bit_from_local$) {\n"
|
||||
" result.$name$_ = $name$_;\n");
|
||||
if (GetNumBitsForMessage() > 0) {
|
||||
if (GetNumBits() > 0) {
|
||||
printer->Print(variables_, " $set_has_field_bit_to_local$;\n");
|
||||
}
|
||||
printer->Print("}\n");
|
||||
|
|
@ -297,7 +352,7 @@ void ImmutableEnumFieldGenerator::GenerateBuilderParsingCode(
|
|||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
printer->Print(variables_,
|
||||
"$name$_ = input.readEnum();\n"
|
||||
"$set_has_field_bit_builder$\n");
|
||||
"$set_has_field_bit$\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"int tmpRaw = input.readEnum();\n"
|
||||
|
|
@ -307,7 +362,7 @@ void ImmutableEnumFieldGenerator::GenerateBuilderParsingCode(
|
|||
" mergeUnknownVarintField($number$, tmpRaw);\n"
|
||||
"} else {\n"
|
||||
" $name$_ = tmpRaw;\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
|
|
@ -315,7 +370,7 @@ void ImmutableEnumFieldGenerator::GenerateBuilderParsingCode(
|
|||
void ImmutableEnumFieldGenerator::GenerateSerializationCode(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($is_field_present_message$) {\n"
|
||||
"if ($is_field_present$) {\n"
|
||||
" output.writeEnum($number$, $name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
|
@ -323,7 +378,7 @@ void ImmutableEnumFieldGenerator::GenerateSerializationCode(
|
|||
void ImmutableEnumFieldGenerator::GenerateSerializedSizeCode(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($is_field_present_message$) {\n"
|
||||
"if ($is_field_present$) {\n"
|
||||
" size += com.google.protobuf.CodedOutputStream\n"
|
||||
" .computeEnumSize($number$, $name$_);\n"
|
||||
"}\n");
|
||||
|
|
@ -347,10 +402,8 @@ std::string ImmutableEnumFieldGenerator::GetBoxedType() const {
|
|||
// ===================================================================
|
||||
|
||||
ImmutableEnumOneofFieldGenerator::ImmutableEnumOneofFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int message_bit_index,
|
||||
int builder_bit_index, Context* context)
|
||||
: ImmutableEnumFieldGenerator(descriptor, message_bit_index,
|
||||
builder_bit_index, context) {
|
||||
const FieldDescriptor* descriptor, int bit_index, Context* context)
|
||||
: ImmutableEnumFieldGenerator(descriptor, bit_index, context) {
|
||||
const OneofGeneratorInfo* info =
|
||||
context->GetOneofGeneratorInfo(descriptor->containing_oneof());
|
||||
SetCommonOneofVariables(descriptor, info, &variables_);
|
||||
|
|
@ -358,9 +411,8 @@ ImmutableEnumOneofFieldGenerator::ImmutableEnumOneofFieldGenerator(
|
|||
|
||||
ImmutableEnumOneofFieldGenerator::~ImmutableEnumOneofFieldGenerator() = default;
|
||||
|
||||
void ImmutableEnumOneofFieldGenerator::GenerateMembers(
|
||||
void ImmutableEnumOneofFieldGenerator::GenerateHasMethod(
|
||||
io::Printer* printer) const {
|
||||
PrintExtraFieldInfo(variables_, printer);
|
||||
ABSL_DCHECK(descriptor_->has_presence());
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
|
||||
context_->options());
|
||||
|
|
@ -369,7 +421,10 @@ void ImmutableEnumOneofFieldGenerator::GenerateMembers(
|
|||
" return $has_oneof_case_message$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutableEnumOneofFieldGenerator::GenerateGetValueMethod(
|
||||
io::Printer* printer) const {
|
||||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
|
|
@ -383,6 +438,10 @@ void ImmutableEnumOneofFieldGenerator::GenerateMembers(
|
|||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableEnumOneofFieldGenerator::GenerateGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
|
|
@ -397,7 +456,15 @@ void ImmutableEnumOneofFieldGenerator::GenerateMembers(
|
|||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
|
||||
void ImmutableEnumOneofFieldGenerator::GenerateMembers(
|
||||
io::Printer* printer) const {
|
||||
PrintExtraFieldInfo(variables_, printer);
|
||||
GenerateHasMethod(printer);
|
||||
GenerateGetValueMethod(printer);
|
||||
GenerateGetMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutableEnumOneofFieldGenerator::GenerateBuilderHasMethod(
|
||||
io::Printer* printer) const {
|
||||
ABSL_DCHECK(descriptor_->has_presence());
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
|
||||
|
|
@ -408,7 +475,10 @@ void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
|
|||
" return $has_oneof_case_message$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutableEnumOneofFieldGenerator::GenerateBuilderGetValueMethod(
|
||||
io::Printer* printer) const {
|
||||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
|
|
@ -422,6 +492,12 @@ void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
|
|||
" return $default_number$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableEnumOneofFieldGenerator::GenerateBuilderSetValueMethod(
|
||||
io::Printer* printer) const {
|
||||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -435,6 +511,10 @@ void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
|
|||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableEnumOneofFieldGenerator::GenerateBuilderGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
|
|
@ -448,7 +528,10 @@ void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
|
|||
" return $default$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutableEnumOneofFieldGenerator::GenerateBuilderSetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -462,7 +545,10 @@ void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
|
|||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void ImmutableEnumOneofFieldGenerator::GenerateBuilderClearMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -479,6 +565,16 @@ void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
|
|||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
|
||||
io::Printer* printer) const {
|
||||
GenerateBuilderHasMethod(printer);
|
||||
GenerateBuilderGetValueMethod(printer);
|
||||
GenerateBuilderSetValueMethod(printer);
|
||||
GenerateBuilderGetMethod(printer);
|
||||
GenerateBuilderSetMethod(printer);
|
||||
GenerateBuilderClearMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutableEnumOneofFieldGenerator::GenerateBuilderClearCode(
|
||||
io::Printer* printer) const {
|
||||
// No-op: Enum fields in oneofs are correctly cleared by clearing the oneof
|
||||
|
|
@ -573,39 +669,51 @@ void ImmutableEnumOneofFieldGenerator::GenerateHashCode(
|
|||
// ===================================================================
|
||||
|
||||
RepeatedImmutableEnumFieldGenerator::RepeatedImmutableEnumFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int message_bit_index,
|
||||
int builder_bit_index, Context* context)
|
||||
: ImmutableEnumFieldGenerator(descriptor, message_bit_index,
|
||||
builder_bit_index, context) {}
|
||||
const FieldDescriptor* descriptor, int bit_index, Context* context)
|
||||
: ImmutableEnumFieldGenerator(descriptor, bit_index, context) {}
|
||||
|
||||
RepeatedImmutableEnumFieldGenerator::~RepeatedImmutableEnumFieldGenerator() =
|
||||
default;
|
||||
|
||||
int RepeatedImmutableEnumFieldGenerator::GetNumBitsForMessage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceMembers(
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceGetListMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$java.util.List<$type$> get$capitalized_name$List();\n");
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceGetCountMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$int get$capitalized_name$Count();\n");
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$$type$ get$capitalized_name$(int index);\n");
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceGetValueListMethod(
|
||||
io::Printer* printer) const {
|
||||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$java.util.List<java.lang.Integer>\n"
|
||||
"get$capitalized_name$ValueList();\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceGetValueMethod(
|
||||
io::Printer* printer) const {
|
||||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
WriteFieldEnumValueAccessorDocComment(
|
||||
printer, descriptor_, LIST_INDEXED_GETTER, context_->options());
|
||||
printer->Print(variables_,
|
||||
|
|
@ -613,6 +721,85 @@ void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceMembers(
|
|||
}
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateInterfaceMembers(
|
||||
io::Printer* printer) const {
|
||||
GenerateInterfaceGetListMethod(printer);
|
||||
GenerateInterfaceGetCountMethod(printer);
|
||||
GenerateInterfaceGetMethod(printer);
|
||||
GenerateInterfaceGetValueListMethod(printer);
|
||||
GenerateInterfaceGetValueMethod(printer);
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateGetListMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public java.util.List<$type$> "
|
||||
"${$get$capitalized_name$List$}$() {\n"
|
||||
" return new com.google.protobuf.Internal.IntListAdapter<\n"
|
||||
" $type$>($name$_, $name$_converter_);\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateGetCountMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
|
||||
" return $name$_.size();\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
|
||||
" return $name$_converter_.convert($name$_.getInt(index));\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateGetValueListMethod(
|
||||
io::Printer* printer) const {
|
||||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public java.util.List<java.lang.Integer>\n"
|
||||
"${$get$capitalized_name$ValueList$}$() {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateGetValueMethod(
|
||||
io::Printer* printer) const {
|
||||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
WriteFieldEnumValueAccessorDocComment(
|
||||
printer, descriptor_, LIST_INDEXED_GETTER, context_->options());
|
||||
printer->Print(variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public int "
|
||||
"${$get$capitalized_name$Value$}$(int index) {\n"
|
||||
" return $name$_.getInt(index);\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateMembers(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(
|
||||
|
|
@ -631,64 +818,19 @@ void RepeatedImmutableEnumFieldGenerator::GenerateMembers(
|
|||
" }\n"
|
||||
" };\n");
|
||||
PrintExtraFieldInfo(variables_, printer);
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public java.util.List<$type$> "
|
||||
"${$get$capitalized_name$List$}$() {\n"
|
||||
" return new com.google.protobuf.Internal.IntListAdapter<\n"
|
||||
" $type$>($name$_, $name$_converter_);\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
|
||||
" return $name$_.size();\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
|
||||
" return $name$_converter_.convert($name$_.getInt(index));\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public java.util.List<java.lang.Integer>\n"
|
||||
"${$get$capitalized_name$ValueList$}$() {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
WriteFieldEnumValueAccessorDocComment(
|
||||
printer, descriptor_, LIST_INDEXED_GETTER, context_->options());
|
||||
printer->Print(variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public int "
|
||||
"${$get$capitalized_name$Value$}$(int index) {\n"
|
||||
" return $name$_.getInt(index);\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
GenerateGetListMethod(printer);
|
||||
GenerateGetCountMethod(printer);
|
||||
GenerateGetMethod(printer);
|
||||
GenerateGetValueListMethod(printer);
|
||||
GenerateGetValueMethod(printer);
|
||||
|
||||
if (descriptor_->is_packed()) {
|
||||
printer->Print(variables_, "private int $name$MemoizedSerializedSize;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateEnsureIsMutableMethod(
|
||||
io::Printer* printer) const {
|
||||
// We use one method and pass -1 when capacity is unknown to control class
|
||||
// size.
|
||||
printer->Print(
|
||||
variables_,
|
||||
"private $field_list_type$ $name$_ = $empty_list$;\n"
|
||||
|
|
@ -696,23 +838,26 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
|||
" if (!$name$_.isModifiable()) {\n"
|
||||
" $name$_ = makeMutableCopy($name$_, capacity);\n"
|
||||
" }\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderGetListMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
// Note: We return an unmodifiable list because otherwise the caller
|
||||
// could hold on to the returned list and modify it after the message
|
||||
// has been built, thus mutating the message which is supposed to be
|
||||
// immutable.
|
||||
"$deprecation$public java.util.List<$type$> "
|
||||
"${$get$capitalized_name$List$}$() {\n"
|
||||
" return new com.google.protobuf.Internal.IntListAdapter<\n"
|
||||
" $type$>($name$_, $name$_converter_);\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderGetCountMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
|
|
@ -721,6 +866,10 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
|||
" return $name$_.size();\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
|
|
@ -729,6 +878,10 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
|||
" return $name$_converter_.convert($name$_.getInt(index));\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderSetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -742,6 +895,10 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
|||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderAddMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -755,6 +912,10 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
|||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderAddAllMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -769,6 +930,10 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
|||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderClearMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -776,12 +941,15 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
|||
variables_,
|
||||
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
|
||||
" $name$_ = $empty_list$;\n"
|
||||
" $clear_has_field_bit_builder$\n"
|
||||
" $clear_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderGetValueListMethod(
|
||||
io::Printer* printer) const {
|
||||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER,
|
||||
context_->options());
|
||||
|
|
@ -792,6 +960,12 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
|||
" return $name$_;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderGetValueMethod(
|
||||
io::Printer* printer) const {
|
||||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
WriteFieldEnumValueAccessorDocComment(
|
||||
printer, descriptor_, LIST_INDEXED_GETTER, context_->options());
|
||||
printer->Print(variables_,
|
||||
|
|
@ -800,6 +974,12 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
|||
" return $name$_.getInt(index);\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderSetValueMethod(
|
||||
io::Printer* printer) const {
|
||||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
WriteFieldEnumValueAccessorDocComment(
|
||||
printer, descriptor_, LIST_INDEXED_SETTER, context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -813,6 +993,12 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
|||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderAddValueMethod(
|
||||
io::Printer* printer) const {
|
||||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_ADDER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -825,6 +1011,12 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
|||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderAddAllValueMethod(
|
||||
io::Printer* printer) const {
|
||||
if (SupportUnknownEnumValue(descriptor_)) {
|
||||
WriteFieldEnumValueAccessorDocComment(printer, descriptor_,
|
||||
LIST_MULTI_ADDER, context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -843,6 +1035,23 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
|||
}
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
|
||||
io::Printer* printer) const {
|
||||
GenerateEnsureIsMutableMethod(printer);
|
||||
GenerateBuilderGetListMethod(printer);
|
||||
GenerateBuilderGetCountMethod(printer);
|
||||
GenerateBuilderGetMethod(printer);
|
||||
GenerateBuilderSetMethod(printer);
|
||||
GenerateBuilderAddMethod(printer);
|
||||
GenerateBuilderAddAllMethod(printer);
|
||||
GenerateBuilderClearMethod(printer);
|
||||
GenerateBuilderGetValueListMethod(printer);
|
||||
GenerateBuilderGetValueMethod(printer);
|
||||
GenerateBuilderSetValueMethod(printer);
|
||||
GenerateBuilderAddValueMethod(printer);
|
||||
GenerateBuilderAddAllValueMethod(printer);
|
||||
}
|
||||
|
||||
void RepeatedImmutableEnumFieldGenerator::
|
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
|
||||
// noop for enums
|
||||
|
|
@ -870,7 +1079,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateMergingCode(
|
|||
" if ($name$_.isEmpty()) {\n"
|
||||
" $name$_ = other.$name$_;\n"
|
||||
" $name_make_immutable$;\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" } else {\n"
|
||||
" ensure$capitalized_name$IsMutable(/* capacity= */ -1);\n"
|
||||
" $name$_.addAll(other.$name$_);\n"
|
||||
|
|
|
|||
|
|
@ -38,8 +38,7 @@ namespace java {
|
|||
class ImmutableEnumFieldGenerator : public ImmutableFieldGenerator {
|
||||
public:
|
||||
explicit ImmutableEnumFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex, int builderBitIndex,
|
||||
Context* context);
|
||||
int bit_index, Context* context);
|
||||
ImmutableEnumFieldGenerator(const ImmutableEnumFieldGenerator&) = delete;
|
||||
ImmutableEnumFieldGenerator& operator=(const ImmutableEnumFieldGenerator&) =
|
||||
delete;
|
||||
|
|
@ -47,7 +46,7 @@ class ImmutableEnumFieldGenerator : public ImmutableFieldGenerator {
|
|||
|
||||
// implements ImmutableFieldGenerator
|
||||
// ---------------------------------------
|
||||
int GetNumBitsForMessage() const override;
|
||||
|
||||
void GenerateInterfaceMembers(io::Printer* printer) const override;
|
||||
void GenerateMembers(io::Printer* printer) const override;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const override;
|
||||
|
|
@ -65,14 +64,27 @@ class ImmutableEnumFieldGenerator : public ImmutableFieldGenerator {
|
|||
|
||||
std::string GetBoxedType() const override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
void GenerateInterfaceHasMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetValueMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetMethod(io::Printer* printer) const;
|
||||
|
||||
void GenerateHasMethod(io::Printer* printer) const;
|
||||
void GenerateGetValueMethod(io::Printer* printer) const;
|
||||
void GenerateGetMethod(io::Printer* printer) const;
|
||||
|
||||
void GenerateBuilderHasMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetValueMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderSetValueMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderSetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderClearMethod(io::Printer* printer) const;
|
||||
};
|
||||
|
||||
class ImmutableEnumOneofFieldGenerator : public ImmutableEnumFieldGenerator {
|
||||
public:
|
||||
ImmutableEnumOneofFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex, int builderBitIndex,
|
||||
Context* context);
|
||||
int bit_index, Context* context);
|
||||
ImmutableEnumOneofFieldGenerator(const ImmutableEnumOneofFieldGenerator&) =
|
||||
delete;
|
||||
ImmutableEnumOneofFieldGenerator& operator=(
|
||||
|
|
@ -89,13 +101,25 @@ class ImmutableEnumOneofFieldGenerator : public ImmutableEnumFieldGenerator {
|
|||
void GenerateSerializedSizeCode(io::Printer* printer) const override;
|
||||
void GenerateEqualsCode(io::Printer* printer) const override;
|
||||
void GenerateHashCode(io::Printer* printer) const override;
|
||||
|
||||
private:
|
||||
void GenerateHasMethod(io::Printer* printer) const;
|
||||
void GenerateGetValueMethod(io::Printer* printer) const;
|
||||
void GenerateGetMethod(io::Printer* printer) const;
|
||||
|
||||
void GenerateBuilderHasMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetValueMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderSetValueMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderSetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderClearMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderParserMethod(io::Printer* printer) const;
|
||||
};
|
||||
|
||||
class RepeatedImmutableEnumFieldGenerator : public ImmutableEnumFieldGenerator {
|
||||
public:
|
||||
explicit RepeatedImmutableEnumFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int messageBitIndex,
|
||||
int builderBitIndex, Context* context);
|
||||
const FieldDescriptor* descriptor, int bit_index, Context* context);
|
||||
RepeatedImmutableEnumFieldGenerator(
|
||||
const RepeatedImmutableEnumFieldGenerator&) = delete;
|
||||
RepeatedImmutableEnumFieldGenerator& operator=(
|
||||
|
|
@ -103,7 +127,6 @@ class RepeatedImmutableEnumFieldGenerator : public ImmutableEnumFieldGenerator {
|
|||
~RepeatedImmutableEnumFieldGenerator() override;
|
||||
|
||||
// implements ImmutableFieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const override;
|
||||
void GenerateInterfaceMembers(io::Printer* printer) const override;
|
||||
void GenerateMembers(io::Printer* printer) const override;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const override;
|
||||
|
|
@ -122,6 +145,33 @@ class RepeatedImmutableEnumFieldGenerator : public ImmutableEnumFieldGenerator {
|
|||
void GenerateHashCode(io::Printer* printer) const override;
|
||||
|
||||
std::string GetBoxedType() const override;
|
||||
|
||||
private:
|
||||
void GenerateInterfaceGetListMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetCountMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetValueListMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetValueMethod(io::Printer* printer) const;
|
||||
|
||||
void GenerateGetListMethod(io::Printer* printer) const;
|
||||
void GenerateGetCountMethod(io::Printer* printer) const;
|
||||
void GenerateGetMethod(io::Printer* printer) const;
|
||||
void GenerateGetValueListMethod(io::Printer* printer) const;
|
||||
void GenerateGetValueMethod(io::Printer* printer) const;
|
||||
|
||||
void GenerateEnsureIsMutableMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetListMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetCountMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderSetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderAddMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderAddAllMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderClearMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetValueListMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetValueMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderSetValueMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderAddValueMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderAddAllValueMethod(io::Printer* printer) const;
|
||||
};
|
||||
|
||||
} // namespace java
|
||||
|
|
|
|||
|
|
@ -9,11 +9,9 @@ namespace compiler {
|
|||
namespace java {
|
||||
|
||||
ImmutableFieldGenerator::ImmutableFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
|
||||
Context* context)
|
||||
const FieldDescriptor* descriptor, int bit_index, Context* context)
|
||||
: descriptor_(descriptor),
|
||||
message_bit_index_(messageBitIndex),
|
||||
builder_bit_index_(builderBitIndex),
|
||||
bit_index_(bit_index),
|
||||
context_(context),
|
||||
name_resolver_(context->GetNameResolver()) {}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,16 +18,13 @@ class ClassNameResolver; // name_resolver.h
|
|||
class ImmutableFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit ImmutableFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex, int builderBitIndex,
|
||||
Context* context);
|
||||
int bit_index, Context* context);
|
||||
ImmutableFieldGenerator(const ImmutableFieldGenerator&) = delete;
|
||||
ImmutableFieldGenerator& operator=(const ImmutableFieldGenerator&) = delete;
|
||||
~ImmutableFieldGenerator() override = default;
|
||||
|
||||
int GetMessageBitIndex() const { return message_bit_index_; }
|
||||
int GetBuilderBitIndex() const { return builder_bit_index_; }
|
||||
virtual int GetNumBitsForMessage() const = 0;
|
||||
constexpr int GetNumBitsForBuilder() const { return 1; }
|
||||
int GetBitIndex() const { return bit_index_; }
|
||||
constexpr int GetNumBits() const { return 1; }
|
||||
virtual void GenerateInterfaceMembers(io::Printer* printer) const = 0;
|
||||
virtual void GenerateMembers(io::Printer* printer) const = 0;
|
||||
virtual void GenerateBuilderMembers(io::Printer* printer) const = 0;
|
||||
|
|
@ -52,8 +49,7 @@ class ImmutableFieldGenerator : public FieldGenerator {
|
|||
|
||||
protected:
|
||||
const FieldDescriptor* descriptor_;
|
||||
int message_bit_index_;
|
||||
int builder_bit_index_;
|
||||
int bit_index_;
|
||||
Context* context_;
|
||||
ClassNameResolver* name_resolver_;
|
||||
absl::flat_hash_map<absl::string_view, std::string> variables_;
|
||||
|
|
|
|||
|
|
@ -31,58 +31,57 @@ namespace java {
|
|||
namespace {
|
||||
|
||||
std::unique_ptr<ImmutableFieldGenerator> MakeImmutableGenerator(
|
||||
const FieldDescriptor* field, int messageBitIndex, int builderBitIndex,
|
||||
Context* context) {
|
||||
const FieldDescriptor* field, int bit_index, Context* context) {
|
||||
if (field->is_repeated()) {
|
||||
switch (GetJavaType(field)) {
|
||||
case JAVATYPE_MESSAGE:
|
||||
if (IsMapEntry(field->message_type())) {
|
||||
return std::make_unique<ImmutableMapFieldGenerator>(
|
||||
field, messageBitIndex, builderBitIndex, context);
|
||||
return std::make_unique<ImmutableMapFieldGenerator>(field, bit_index,
|
||||
context);
|
||||
} else {
|
||||
return std::make_unique<RepeatedImmutableMessageFieldGenerator>(
|
||||
field, messageBitIndex, builderBitIndex, context);
|
||||
field, bit_index, context);
|
||||
}
|
||||
case JAVATYPE_ENUM:
|
||||
return std::make_unique<RepeatedImmutableEnumFieldGenerator>(
|
||||
field, messageBitIndex, builderBitIndex, context);
|
||||
field, bit_index, context);
|
||||
case JAVATYPE_STRING:
|
||||
return std::make_unique<RepeatedImmutableStringFieldGenerator>(
|
||||
field, messageBitIndex, builderBitIndex, context);
|
||||
field, bit_index, context);
|
||||
default:
|
||||
return std::make_unique<RepeatedImmutablePrimitiveFieldGenerator>(
|
||||
field, messageBitIndex, builderBitIndex, context);
|
||||
field, bit_index, context);
|
||||
}
|
||||
} else {
|
||||
if (IsRealOneof(field)) {
|
||||
switch (GetJavaType(field)) {
|
||||
case JAVATYPE_MESSAGE:
|
||||
return std::make_unique<ImmutableMessageOneofFieldGenerator>(
|
||||
field, messageBitIndex, builderBitIndex, context);
|
||||
field, bit_index, context);
|
||||
case JAVATYPE_ENUM:
|
||||
return std::make_unique<ImmutableEnumOneofFieldGenerator>(
|
||||
field, messageBitIndex, builderBitIndex, context);
|
||||
field, bit_index, context);
|
||||
case JAVATYPE_STRING:
|
||||
return std::make_unique<ImmutableStringOneofFieldGenerator>(
|
||||
field, messageBitIndex, builderBitIndex, context);
|
||||
field, bit_index, context);
|
||||
default:
|
||||
return std::make_unique<ImmutablePrimitiveOneofFieldGenerator>(
|
||||
field, messageBitIndex, builderBitIndex, context);
|
||||
field, bit_index, context);
|
||||
}
|
||||
} else {
|
||||
switch (GetJavaType(field)) {
|
||||
case JAVATYPE_MESSAGE:
|
||||
return std::make_unique<ImmutableMessageFieldGenerator>(
|
||||
field, messageBitIndex, builderBitIndex, context);
|
||||
field, bit_index, context);
|
||||
case JAVATYPE_ENUM:
|
||||
return std::make_unique<ImmutableEnumFieldGenerator>(
|
||||
field, messageBitIndex, builderBitIndex, context);
|
||||
return std::make_unique<ImmutableEnumFieldGenerator>(field, bit_index,
|
||||
context);
|
||||
case JAVATYPE_STRING:
|
||||
return std::make_unique<ImmutableStringFieldGenerator>(
|
||||
field, messageBitIndex, builderBitIndex, context);
|
||||
field, bit_index, context);
|
||||
default:
|
||||
return std::make_unique<ImmutablePrimitiveFieldGenerator>(
|
||||
field, messageBitIndex, builderBitIndex, context);
|
||||
field, bit_index, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -94,15 +93,12 @@ FieldGeneratorMap<ImmutableFieldGenerator> MakeImmutableFieldGenerators(
|
|||
const Descriptor* descriptor, Context* context) {
|
||||
// Construct all the FieldGenerators and assign them bit indices for their
|
||||
// bit fields.
|
||||
int messageBitIndex = 0;
|
||||
int builderBitIndex = 0;
|
||||
int bit_index = 0;
|
||||
FieldGeneratorMap<ImmutableFieldGenerator> ret(descriptor);
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
const FieldDescriptor* field = descriptor->field(i);
|
||||
auto generator = MakeImmutableGenerator(field, messageBitIndex,
|
||||
builderBitIndex, context);
|
||||
messageBitIndex += generator->GetNumBitsForMessage();
|
||||
builderBitIndex += generator->GetNumBitsForBuilder();
|
||||
auto generator = MakeImmutableGenerator(field, bit_index, context);
|
||||
bit_index += generator->GetNumBits();
|
||||
ret.Add(field, std::move(generator));
|
||||
}
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -52,10 +52,8 @@ std::string WireType(const FieldDescriptor* field) {
|
|||
} // namespace
|
||||
|
||||
ImmutableMapFieldGenerator::ImmutableMapFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
|
||||
Context* context)
|
||||
: ImmutableFieldGenerator(descriptor, messageBitIndex, builderBitIndex,
|
||||
context) {
|
||||
const FieldDescriptor* descriptor, int bit_index, Context* context)
|
||||
: ImmutableFieldGenerator(descriptor, bit_index, context) {
|
||||
SetMessageVariables(context->GetFieldGeneratorInfo(descriptor));
|
||||
}
|
||||
|
||||
|
|
@ -164,28 +162,34 @@ void ImmutableMapFieldGenerator::SetMessageVariables(
|
|||
variables_["descriptor"] = absl::StrCat(
|
||||
name_resolver->GetImmutableClassName(descriptor_->file()), ".internal_",
|
||||
UniqueFileScopeIdentifier(descriptor_->message_type()), "_descriptor, ");
|
||||
variables_["get_has_field_bit_builder"] = GenerateGetBit(builder_bit_index_);
|
||||
variables_["get_has_field_bit"] = GenerateGetBit(bit_index_);
|
||||
variables_["get_has_field_bit_from_local"] =
|
||||
GenerateGetBitFromLocal(builder_bit_index_);
|
||||
variables_["set_has_field_bit_builder"] =
|
||||
absl::StrCat(GenerateSetBit(builder_bit_index_), ";");
|
||||
variables_["clear_has_field_bit_builder"] =
|
||||
absl::StrCat(GenerateClearBit(builder_bit_index_), ";");
|
||||
GenerateGetBitFromLocal(bit_index_);
|
||||
variables_["set_has_field_bit"] =
|
||||
absl::StrCat(GenerateSetBit(bit_index_), ";");
|
||||
variables_["clear_has_field_bit"] =
|
||||
absl::StrCat(GenerateClearBit(bit_index_), ";");
|
||||
}
|
||||
|
||||
int ImmutableMapFieldGenerator::GetNumBitsForMessage() const { return 0; }
|
||||
void ImmutableMapFieldGenerator::GenerateInterfaceMembers(
|
||||
void ImmutableMapFieldGenerator::GenerateInterfaceGetCountMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$int ${$get$capitalized_name$Count$}$();\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateInterfaceContainsMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$boolean ${$contains$capitalized_name$$}$(\n"
|
||||
" $key_type$ key);\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateInterfaceGetMapMethod(
|
||||
io::Printer* printer) const {
|
||||
const FieldDescriptor* value = MapValueField(descriptor_);
|
||||
if (GetJavaType(value) == JAVATYPE_ENUM) {
|
||||
if (google::protobuf::internal::IsOss()) {
|
||||
|
|
@ -204,49 +208,6 @@ void ImmutableMapFieldGenerator::GenerateInterfaceMembers(
|
|||
"$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
|
||||
"${$get$capitalized_name$Map$}$();\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$$value_enum_type_pass_through_nullness$ "
|
||||
"${$get$capitalized_name$OrDefault$}$(\n"
|
||||
" $key_type$ key,\n"
|
||||
" $value_enum_type_pass_through_nullness$ "
|
||||
" defaultValue);\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$$value_enum_type$ ${$get$capitalized_name$OrThrow$}$(\n"
|
||||
" $key_type$ key);\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
if (SupportUnknownEnumValue(value)) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"/**\n"
|
||||
" * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
|
||||
" */\n"
|
||||
"@java.lang.Deprecated\n"
|
||||
"java.util.Map<$type_parameters$>\n"
|
||||
"${$get$capitalized_name$Value$}$();\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$java.util.Map<$type_parameters$>\n"
|
||||
"${$get$capitalized_name$ValueMap$}$();\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$$value_type_pass_through_nullness$ "
|
||||
"${$get$capitalized_name$ValueOrDefault$}$(\n"
|
||||
" $key_type$ key,\n"
|
||||
" $value_type_pass_through_nullness$ defaultValue);\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$$value_type$ ${$get$capitalized_name$ValueOrThrow$}$(\n"
|
||||
" $key_type$ key);\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
} else {
|
||||
if (google::protobuf::internal::IsOss()) {
|
||||
printer->Print(variables_,
|
||||
|
|
@ -263,6 +224,22 @@ void ImmutableMapFieldGenerator::GenerateInterfaceMembers(
|
|||
"$deprecation$java.util.Map<$type_parameters$>\n"
|
||||
"${$get$capitalized_name$Map$}$();\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateInterfaceGetOrDefaultMethod(
|
||||
io::Printer* printer) const {
|
||||
const FieldDescriptor* value = MapValueField(descriptor_);
|
||||
if (GetJavaType(value) == JAVATYPE_ENUM) {
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$$value_enum_type_pass_through_nullness$ "
|
||||
"${$get$capitalized_name$OrDefault$}$(\n"
|
||||
" $key_type$ key,\n"
|
||||
" $value_enum_type_pass_through_nullness$ "
|
||||
" defaultValue);\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
} else {
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$$value_type_pass_through_nullness$ "
|
||||
|
|
@ -270,6 +247,20 @@ void ImmutableMapFieldGenerator::GenerateInterfaceMembers(
|
|||
" $key_type$ key,\n"
|
||||
" $value_type_pass_through_nullness$ defaultValue);\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateInterfaceGetOrThrowMethod(
|
||||
io::Printer* printer) const {
|
||||
const FieldDescriptor* value = MapValueField(descriptor_);
|
||||
if (GetJavaType(value) == JAVATYPE_ENUM) {
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$$value_enum_type$ ${$get$capitalized_name$OrThrow$}$(\n"
|
||||
" $key_type$ key);\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
} else {
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
|
|
@ -279,6 +270,65 @@ void ImmutableMapFieldGenerator::GenerateInterfaceMembers(
|
|||
}
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateInterfaceGetValueMapMethod(
|
||||
io::Printer* printer) const {
|
||||
const FieldDescriptor* value = MapValueField(descriptor_);
|
||||
if (GetJavaType(value) == JAVATYPE_ENUM && SupportUnknownEnumValue(value)) {
|
||||
printer->Print(variables_,
|
||||
"/**\n"
|
||||
" * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
|
||||
" */\n"
|
||||
"@java.lang.Deprecated\n"
|
||||
"java.util.Map<$type_parameters$>\n"
|
||||
"${$get$capitalized_name$Value$}$();\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$java.util.Map<$type_parameters$>\n"
|
||||
"${$get$capitalized_name$ValueMap$}$();\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateInterfaceGetValueOrDefaultMethod(
|
||||
io::Printer* printer) const {
|
||||
const FieldDescriptor* value = MapValueField(descriptor_);
|
||||
if (GetJavaType(value) == JAVATYPE_ENUM && SupportUnknownEnumValue(value)) {
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$$value_type_pass_through_nullness$ "
|
||||
"${$get$capitalized_name$ValueOrDefault$}$(\n"
|
||||
" $key_type$ key,\n"
|
||||
" $value_type_pass_through_nullness$ defaultValue);\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateInterfaceGetValueOrThrowMethod(
|
||||
io::Printer* printer) const {
|
||||
const FieldDescriptor* value = MapValueField(descriptor_);
|
||||
if (GetJavaType(value) == JAVATYPE_ENUM && SupportUnknownEnumValue(value)) {
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$$value_type$ ${$get$capitalized_name$ValueOrThrow$}$(\n"
|
||||
" $key_type$ key);\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateInterfaceMembers(
|
||||
io::Printer* printer) const {
|
||||
GenerateInterfaceGetCountMethod(printer);
|
||||
GenerateInterfaceContainsMethod(printer);
|
||||
GenerateInterfaceGetMapMethod(printer);
|
||||
GenerateInterfaceGetOrDefaultMethod(printer);
|
||||
GenerateInterfaceGetOrThrowMethod(printer);
|
||||
GenerateInterfaceGetValueMapMethod(printer);
|
||||
GenerateInterfaceGetValueOrDefaultMethod(printer);
|
||||
GenerateInterfaceGetValueOrThrowMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateMembers(io::Printer* printer) const {
|
||||
printer->Print(
|
||||
variables_,
|
||||
|
|
@ -328,6 +378,183 @@ void ImmutableMapFieldGenerator::GenerateMembers(io::Printer* printer) const {
|
|||
GenerateMapGetters(printer);
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateBuilderClearMethod(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
|
||||
" $clear_has_field_bit$\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap()\n"
|
||||
" .clear();\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateBuilderRemoveMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder ${$remove$capitalized_name$$}$(\n"
|
||||
" $key_type$ key) {\n"
|
||||
" $key_null_check$\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap()\n"
|
||||
" .remove(key);\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateBuilderPutMethod(
|
||||
io::Printer* printer) const {
|
||||
const FieldDescriptor* value = MapValueField(descriptor_);
|
||||
if (GetJavaType(value) == JAVATYPE_ENUM) {
|
||||
if (google::protobuf::internal::IsOss()) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"/**\n"
|
||||
" * Use alternate mutation accessors instead.\n"
|
||||
" */\n"
|
||||
"@java.lang.Deprecated\n"
|
||||
"public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
|
||||
" ${$getMutable$capitalized_name$$}$() {\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" return internalGetAdapted$capitalized_name$Map(\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap());\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder ${$put$capitalized_name$$}$(\n"
|
||||
" $key_type$ key,\n"
|
||||
" $value_enum_type$ value) {\n"
|
||||
" $key_null_check$\n"
|
||||
" $value_null_check$\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap()\n"
|
||||
" .put(key, $name$ValueConverter.doBackward(value));\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
} else {
|
||||
if (google::protobuf::internal::IsOss()) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"/**\n"
|
||||
" * Use alternate mutation accessors instead.\n"
|
||||
" */\n"
|
||||
"@java.lang.Deprecated\n"
|
||||
"public java.util.Map<$type_parameters$>\n"
|
||||
" ${$getMutable$capitalized_name$$}$() {\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" return internalGetMutable$capitalized_name$().getMutableMap();\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder ${$put$capitalized_name$$}$(\n"
|
||||
" $key_type$ key,\n"
|
||||
" $value_type$ value) {\n"
|
||||
" $key_null_check$\n"
|
||||
" $value_null_check$\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap()\n"
|
||||
" .put(key, value);\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateBuilderPutAllMethod(
|
||||
io::Printer* printer) const {
|
||||
const FieldDescriptor* value = MapValueField(descriptor_);
|
||||
if (GetJavaType(value) == JAVATYPE_ENUM) {
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public Builder ${$putAll$capitalized_name$$}$(\n"
|
||||
" java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n"
|
||||
" internalGetAdapted$capitalized_name$Map(\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap())\n"
|
||||
" .putAll(values);\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
} else {
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public Builder ${$putAll$capitalized_name$$}$(\n"
|
||||
" java.util.Map<$type_parameters$> values) {\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap()\n"
|
||||
" .putAll(values);\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateBuilderPutValueMethod(
|
||||
io::Printer* printer) const {
|
||||
const FieldDescriptor* value = MapValueField(descriptor_);
|
||||
if (GetJavaType(value) == JAVATYPE_ENUM && SupportUnknownEnumValue(value)) {
|
||||
if (google::protobuf::internal::IsOss()) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"/**\n"
|
||||
" * Use alternate mutation accessors instead.\n"
|
||||
" */\n"
|
||||
"@java.lang.Deprecated\n"
|
||||
"public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
|
||||
"${$getMutable$capitalized_name$Value$}$() {\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" return internalGetMutable$capitalized_name$().getMutableMap();\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public Builder ${$put$capitalized_name$Value$}$(\n"
|
||||
" $key_type$ key,\n"
|
||||
" $value_type$ value) {\n"
|
||||
" $key_null_check$\n"
|
||||
" $value_null_check$\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap()\n"
|
||||
" .put(key, value);\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateBuilderPutAllValueMethod(
|
||||
io::Printer* printer) const {
|
||||
const FieldDescriptor* value = MapValueField(descriptor_);
|
||||
if (GetJavaType(value) == JAVATYPE_ENUM && SupportUnknownEnumValue(value)) {
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public Builder ${$putAll$capitalized_name$Value$}$(\n"
|
||||
" java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap()\n"
|
||||
" .putAll(values);\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateBuilderMembers(
|
||||
io::Printer* printer) const {
|
||||
if (GetJavaType(MapValueField(descriptor_)) == JAVATYPE_MESSAGE) {
|
||||
|
|
@ -354,162 +581,17 @@ void ImmutableMapFieldGenerator::GenerateBuilderMembers(
|
|||
" if (!$name$_.isMutable()) {\n"
|
||||
" $name$_ = $name$_.copy();\n"
|
||||
" }\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
" return $name$_;\n"
|
||||
"}\n");
|
||||
GenerateMapGetters(printer);
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
|
||||
" $clear_has_field_bit_builder$\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap()\n"
|
||||
" .clear();\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder ${$remove$capitalized_name$$}$(\n"
|
||||
" $key_type$ key) {\n"
|
||||
" $key_null_check$\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap()\n"
|
||||
" .remove(key);\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
|
||||
const FieldDescriptor* value = MapValueField(descriptor_);
|
||||
if (GetJavaType(value) == JAVATYPE_ENUM) {
|
||||
if (google::protobuf::internal::IsOss()) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"/**\n"
|
||||
" * Use alternate mutation accessors instead.\n"
|
||||
" */\n"
|
||||
"@java.lang.Deprecated\n"
|
||||
"public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
|
||||
" ${$getMutable$capitalized_name$$}$() {\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" return internalGetAdapted$capitalized_name$Map(\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap());\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder ${$put$capitalized_name$$}$(\n"
|
||||
" $key_type$ key,\n"
|
||||
" $value_enum_type$ value) {\n"
|
||||
" $key_null_check$\n"
|
||||
" $value_null_check$\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap()\n"
|
||||
" .put(key, $name$ValueConverter.doBackward(value));\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public Builder ${$putAll$capitalized_name$$}$(\n"
|
||||
" java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n"
|
||||
" internalGetAdapted$capitalized_name$Map(\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap())\n"
|
||||
" .putAll(values);\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
|
||||
if (SupportUnknownEnumValue(value)) {
|
||||
if (google::protobuf::internal::IsOss()) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"/**\n"
|
||||
" * Use alternate mutation accessors instead.\n"
|
||||
" */\n"
|
||||
"@java.lang.Deprecated\n"
|
||||
"public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
|
||||
"${$getMutable$capitalized_name$Value$}$() {\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" return internalGetMutable$capitalized_name$().getMutableMap();\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public Builder ${$put$capitalized_name$Value$}$(\n"
|
||||
" $key_type$ key,\n"
|
||||
" $value_type$ value) {\n"
|
||||
" $key_null_check$\n"
|
||||
" $value_null_check$\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap()\n"
|
||||
" .put(key, value);\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public Builder ${$putAll$capitalized_name$Value$}$(\n"
|
||||
" java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap()\n"
|
||||
" .putAll(values);\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
} else {
|
||||
if (google::protobuf::internal::IsOss()) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"/**\n"
|
||||
" * Use alternate mutation accessors instead.\n"
|
||||
" */\n"
|
||||
"@java.lang.Deprecated\n"
|
||||
"public java.util.Map<$type_parameters$>\n"
|
||||
" ${$getMutable$capitalized_name$$}$() {\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" return internalGetMutable$capitalized_name$().getMutableMap();\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder ${$put$capitalized_name$$}$(\n"
|
||||
" $key_type$ key,\n"
|
||||
" $value_type$ value) {\n"
|
||||
" $key_null_check$\n"
|
||||
" $value_null_check$\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap()\n"
|
||||
" .put(key, value);\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public Builder ${$putAll$capitalized_name$$}$(\n"
|
||||
" java.util.Map<$type_parameters$> values) {\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap()\n"
|
||||
" .putAll(values);\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
GenerateBuilderClearMethod(printer);
|
||||
GenerateBuilderRemoveMethod(printer);
|
||||
GenerateBuilderPutMethod(printer);
|
||||
GenerateBuilderPutAllMethod(printer);
|
||||
GenerateBuilderPutValueMethod(printer);
|
||||
GenerateBuilderPutAllValueMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateMapGetters(
|
||||
|
|
@ -701,6 +783,108 @@ void ImmutableMapFieldGenerator::GenerateMapGetters(
|
|||
}
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateMessageMapBuilderClearMethod(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
|
||||
" $clear_has_field_bit$\n"
|
||||
" internalGetMutable$capitalized_name$().clear();\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateMessageMapBuilderRemoveMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder ${$remove$capitalized_name$$}$(\n"
|
||||
" $key_type$ key) {\n"
|
||||
" $key_null_check$\n"
|
||||
" internalGetMutable$capitalized_name$().ensureBuilderMap()\n"
|
||||
" .remove(key);\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateMessageMapBuilderPutMethod(
|
||||
io::Printer* printer) const {
|
||||
if (google::protobuf::internal::IsOss()) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"/**\n"
|
||||
" * Use alternate mutation accessors instead.\n"
|
||||
" */\n"
|
||||
"@java.lang.Deprecated\n"
|
||||
"public java.util.Map<$type_parameters$>\n"
|
||||
" ${$getMutable$capitalized_name$$}$() {\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" return internalGetMutable$capitalized_name$().ensureMessageMap();\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder ${$put$capitalized_name$$}$(\n"
|
||||
" $key_type$ key,\n"
|
||||
" $value_type$ value) {\n"
|
||||
" $key_null_check$\n"
|
||||
" $value_null_check$\n"
|
||||
" internalGetMutable$capitalized_name$().ensureBuilderMap()\n"
|
||||
" .put(key, value);\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateMessageMapBuilderPutAllMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public Builder ${$putAll$capitalized_name$$}$(\n"
|
||||
" java.util.Map<$type_parameters$> values) {\n"
|
||||
" for (java.util.Map.Entry<$type_parameters$> e : values.entrySet()) {\n"
|
||||
" java.util.Objects.requireNonNull(e.getKey());\n"
|
||||
" java.util.Objects.requireNonNull(e.getValue());\n"
|
||||
" }\n"
|
||||
" internalGetMutable$capitalized_name$().ensureBuilderMap()\n"
|
||||
" .putAll(values);\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::
|
||||
GenerateMessageMapBuilderPutBuilderIfAbsentMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public $value_builder_type$ "
|
||||
"${$put$capitalized_name$BuilderIfAbsent$}$(\n"
|
||||
" $key_type$ key) {\n"
|
||||
" java.util.Map<$boxed_key_type$, $value_interface_type$> builderMap = "
|
||||
"internalGetMutable$capitalized_name$().ensureBuilderMap();\n"
|
||||
" $value_interface_type$ entry = builderMap.get(key);\n"
|
||||
" if (entry == null) {\n"
|
||||
" entry = $value_type$.newBuilder();\n"
|
||||
" builderMap.put(key, entry);\n"
|
||||
" }\n"
|
||||
" if (entry instanceof $value_type$) {\n"
|
||||
" entry = (($value_type$) entry).toBuilder();\n"
|
||||
" builderMap.put(key, entry);\n"
|
||||
" }\n"
|
||||
" return ($value_builder_type$) entry;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateMessageMapBuilderMembers(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(
|
||||
|
|
@ -761,96 +945,16 @@ void ImmutableMapFieldGenerator::GenerateMessageMapBuilderMembers(
|
|||
" $name$_ = new "
|
||||
"com.google.protobuf.MapFieldBuilder<>($name$Converter);\n"
|
||||
" }\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
" return $name$_;\n"
|
||||
"}\n");
|
||||
GenerateMessageMapGetters(printer);
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
|
||||
" $clear_has_field_bit_builder$\n"
|
||||
" internalGetMutable$capitalized_name$().clear();\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder ${$remove$capitalized_name$$}$(\n"
|
||||
" $key_type$ key) {\n"
|
||||
" $key_null_check$\n"
|
||||
" internalGetMutable$capitalized_name$().ensureBuilderMap()\n"
|
||||
" .remove(key);\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
|
||||
if (google::protobuf::internal::IsOss()) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"/**\n"
|
||||
" * Use alternate mutation accessors instead.\n"
|
||||
" */\n"
|
||||
"@java.lang.Deprecated\n"
|
||||
"public java.util.Map<$type_parameters$>\n"
|
||||
" ${$getMutable$capitalized_name$$}$() {\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" return internalGetMutable$capitalized_name$().ensureMessageMap();\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public Builder ${$put$capitalized_name$$}$(\n"
|
||||
" $key_type$ key,\n"
|
||||
" $value_type$ value) {\n"
|
||||
" $key_null_check$\n"
|
||||
" $value_null_check$\n"
|
||||
" internalGetMutable$capitalized_name$().ensureBuilderMap()\n"
|
||||
" .put(key, value);\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public Builder ${$putAll$capitalized_name$$}$(\n"
|
||||
" java.util.Map<$type_parameters$> values) {\n"
|
||||
" for (java.util.Map.Entry<$type_parameters$> e : values.entrySet()) {\n"
|
||||
" java.util.Objects.requireNonNull(e.getKey());\n"
|
||||
" java.util.Objects.requireNonNull(e.getValue());\n"
|
||||
" }\n"
|
||||
" internalGetMutable$capitalized_name$().ensureBuilderMap()\n"
|
||||
" .putAll(values);\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public $value_builder_type$ "
|
||||
"${$put$capitalized_name$BuilderIfAbsent$}$(\n"
|
||||
" $key_type$ key) {\n"
|
||||
" java.util.Map<$boxed_key_type$, $value_interface_type$> builderMap = "
|
||||
"internalGetMutable$capitalized_name$().ensureBuilderMap();\n"
|
||||
" $value_interface_type$ entry = builderMap.get(key);\n"
|
||||
" if (entry == null) {\n"
|
||||
" entry = $value_type$.newBuilder();\n"
|
||||
" builderMap.put(key, entry);\n"
|
||||
" }\n"
|
||||
" if (entry instanceof $value_type$) {\n"
|
||||
" entry = (($value_type$) entry).toBuilder();\n"
|
||||
" builderMap.put(key, entry);\n"
|
||||
" }\n"
|
||||
" return ($value_builder_type$) entry;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
GenerateMessageMapBuilderClearMethod(printer);
|
||||
GenerateMessageMapBuilderRemoveMethod(printer);
|
||||
GenerateMessageMapBuilderPutMethod(printer);
|
||||
GenerateMessageMapBuilderPutAllMethod(printer);
|
||||
GenerateMessageMapBuilderPutBuilderIfAbsentMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateMessageMapGetters(
|
||||
|
|
@ -948,7 +1052,7 @@ void ImmutableMapFieldGenerator::GenerateMergingCode(
|
|||
printer->Print(variables_,
|
||||
"internalGetMutable$capitalized_name$().mergeFrom(\n"
|
||||
" other.internalGet$capitalized_name$());\n"
|
||||
"$set_has_field_bit_builder$\n");
|
||||
"$set_has_field_bit$\n");
|
||||
}
|
||||
|
||||
void ImmutableMapFieldGenerator::GenerateBuildingCode(
|
||||
|
|
@ -981,7 +1085,7 @@ void ImmutableMapFieldGenerator::GenerateBuilderParsingCode(
|
|||
" $default_entry$.getParserForType(), extensionRegistry);\n"
|
||||
"internalGetMutable$capitalized_name$().ensureBuilderMap().put(\n"
|
||||
" $name$__.getKey(), $name$__.getValue());\n"
|
||||
"$set_has_field_bit_builder$\n");
|
||||
"$set_has_field_bit$\n");
|
||||
return;
|
||||
}
|
||||
if (!SupportUnknownEnumValue(value) && type == JAVATYPE_ENUM) {
|
||||
|
|
@ -995,7 +1099,7 @@ void ImmutableMapFieldGenerator::GenerateBuilderParsingCode(
|
|||
"} else {\n"
|
||||
" internalGetMutable$capitalized_name$().getMutableMap().put(\n"
|
||||
" $name$__.getKey(), $name$__.getValue());\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
"}\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -1005,7 +1109,7 @@ void ImmutableMapFieldGenerator::GenerateBuilderParsingCode(
|
|||
" $default_entry$.getParserForType(), extensionRegistry);\n"
|
||||
"internalGetMutable$capitalized_name$().getMutableMap().put(\n"
|
||||
" $name$__.getKey(), $name$__.getValue());\n"
|
||||
"$set_has_field_bit_builder$\n");
|
||||
"$set_has_field_bit$\n");
|
||||
}
|
||||
void ImmutableMapFieldGenerator::GenerateSerializationCode(
|
||||
io::Printer* printer) const {
|
||||
|
|
|
|||
|
|
@ -21,12 +21,11 @@ namespace java {
|
|||
class ImmutableMapFieldGenerator : public ImmutableFieldGenerator {
|
||||
public:
|
||||
explicit ImmutableMapFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex, int builderBitIndex,
|
||||
Context* context);
|
||||
int bit_index, Context* context);
|
||||
~ImmutableMapFieldGenerator() override = default;
|
||||
|
||||
// implements ImmutableFieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const override;
|
||||
|
||||
void GenerateInterfaceMembers(io::Printer* printer) const override;
|
||||
void GenerateMembers(io::Printer* printer) const override;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const override;
|
||||
|
|
@ -49,6 +48,29 @@ class ImmutableMapFieldGenerator : public ImmutableFieldGenerator {
|
|||
void GenerateMapGetters(io::Printer* printer) const;
|
||||
void GenerateMessageMapBuilderMembers(io::Printer* printer) const;
|
||||
void GenerateMessageMapGetters(io::Printer* printer) const;
|
||||
|
||||
void GenerateInterfaceGetCountMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceContainsMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetMapMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetOrDefaultMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetOrThrowMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetValueMapMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetValueOrDefaultMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetValueOrThrowMethod(io::Printer* printer) const;
|
||||
|
||||
void GenerateBuilderClearMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderRemoveMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderPutMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderPutAllMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderPutValueMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderPutAllValueMethod(io::Printer* printer) const;
|
||||
|
||||
void GenerateMessageMapBuilderClearMethod(io::Printer* printer) const;
|
||||
void GenerateMessageMapBuilderRemoveMethod(io::Printer* printer) const;
|
||||
void GenerateMessageMapBuilderPutMethod(io::Printer* printer) const;
|
||||
void GenerateMessageMapBuilderPutAllMethod(io::Printer* printer) const;
|
||||
void GenerateMessageMapBuilderPutBuilderIfAbsentMethod(
|
||||
io::Printer* printer) const;
|
||||
};
|
||||
|
||||
} // namespace java
|
||||
|
|
|
|||
|
|
@ -380,8 +380,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
|
|||
// Integers for bit fields.
|
||||
int totalBits = 0;
|
||||
for (int i = 0; i < descriptor_->field_count(); i++) {
|
||||
totalBits +=
|
||||
field_generators_.get(descriptor_->field(i)).GetNumBitsForMessage();
|
||||
totalBits += field_generators_.get(descriptor_->field(i)).GetNumBits();
|
||||
}
|
||||
int totalInts = (totalBits + 31) / 32;
|
||||
for (int i = 0; i < totalInts; i++) {
|
||||
|
|
|
|||
|
|
@ -188,8 +188,7 @@ void MessageBuilderGenerator::Generate(io::Printer* printer) {
|
|||
// Integers for bit fields.
|
||||
int totalBits = 0;
|
||||
for (int i = 0; i < descriptor_->field_count(); i++) {
|
||||
totalBits +=
|
||||
field_generators_.get(descriptor_->field(i)).GetNumBitsForBuilder();
|
||||
totalBits += field_generators_.get(descriptor_->field(i)).GetNumBits();
|
||||
}
|
||||
int totalInts = (totalBits + 31) / 32;
|
||||
for (int i = 0; i < totalInts; i++) {
|
||||
|
|
@ -720,7 +719,7 @@ int MessageBuilderGenerator::GenerateBuildPartialShard(io::Printer* printer,
|
|||
for (; bit < 32 && next < descriptor_->field_count(); ++next) {
|
||||
const ImmutableFieldGenerator& field =
|
||||
field_generators_.get(descriptor_->field(next));
|
||||
bit += field.GetNumBitsForBuilder();
|
||||
bit += field.GetNumBits();
|
||||
|
||||
// Skip oneof fields that are handled separately
|
||||
if (IsRealOneof(descriptor_->field(next))) {
|
||||
|
|
@ -733,13 +732,13 @@ int MessageBuilderGenerator::GenerateBuildPartialShard(io::Printer* printer,
|
|||
continue;
|
||||
}
|
||||
// Skip fields without presence bits in the builder
|
||||
if (field.GetNumBitsForBuilder() == 0) {
|
||||
if (field.GetNumBits() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Track message bits if necessary
|
||||
if (field.GetNumBitsForMessage() > 0) {
|
||||
int to_bitfield = field.GetMessageBitIndex() / 32;
|
||||
if (field.GetNumBits() > 0) {
|
||||
int to_bitfield = field.GetBitIndex() / 32;
|
||||
if (declared_to_bitfields.count(to_bitfield) == 0) {
|
||||
printer->Print("int to_$bit_field_name$ = 0;\n", "bit_field_name",
|
||||
GetBitFieldName(to_bitfield));
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "google/protobuf/compiler/java/doc_comment.h"
|
||||
#include "google/protobuf/compiler/java/field_common.h"
|
||||
#include "google/protobuf/compiler/java/helpers.h"
|
||||
#include "google/protobuf/compiler/java/full/field_generator.h"
|
||||
#include "google/protobuf/compiler/java/name_resolver.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "google/protobuf/wire_format.h"
|
||||
|
|
@ -37,7 +38,7 @@ namespace {
|
|||
using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
|
||||
|
||||
void SetMessageVariables(
|
||||
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
|
||||
const FieldDescriptor* descriptor, int bit_index,
|
||||
const FieldGeneratorInfo* info, ClassNameResolver* name_resolver,
|
||||
absl::flat_hash_map<absl::string_view, std::string>* variables,
|
||||
Context* context) {
|
||||
|
|
@ -59,27 +60,27 @@ void SetMessageVariables(
|
|||
// For singular messages and builders, one bit is used for the hasField bit.
|
||||
// Note that these have a trailing ";".
|
||||
(*variables)["set_has_field_bit_to_local"] =
|
||||
GenerateSetBitToLocal(messageBitIndex);
|
||||
GenerateSetBitToLocal(bit_index);
|
||||
|
||||
(*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
|
||||
(*variables)["is_field_present"] = GenerateGetBit(bit_index);
|
||||
} else {
|
||||
(*variables)["set_has_field_bit_to_local"] = "";
|
||||
variables->insert({"is_field_present_message",
|
||||
absl::StrCat((*variables)["name"], "_ != null")});
|
||||
variables->insert(
|
||||
{"is_field_present", absl::StrCat((*variables)["name"], "_ != null")});
|
||||
}
|
||||
|
||||
// For repeated builders, one bit is used for whether the array is immutable.
|
||||
(*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex);
|
||||
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
|
||||
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
|
||||
(*variables)["get_mutable_bit_builder"] = GenerateGetBit(bit_index);
|
||||
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(bit_index);
|
||||
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(bit_index);
|
||||
|
||||
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
|
||||
(*variables)["set_has_field_bit_builder"] =
|
||||
absl::StrCat(GenerateSetBit(builderBitIndex), ";");
|
||||
(*variables)["clear_has_field_bit_builder"] =
|
||||
absl::StrCat(GenerateClearBit(builderBitIndex), ";");
|
||||
(*variables)["get_has_field_bit"] = GenerateGetBit(bit_index);
|
||||
(*variables)["set_has_field_bit"] =
|
||||
absl::StrCat(GenerateSetBit(bit_index), ";");
|
||||
(*variables)["clear_has_field_bit"] =
|
||||
absl::StrCat(GenerateClearBit(bit_index), ";");
|
||||
(*variables)["get_has_field_bit_from_local"] =
|
||||
GenerateGetBitFromLocal(builderBitIndex);
|
||||
GenerateGetBitFromLocal(bit_index);
|
||||
|
||||
(*variables)["tag_size"] = absl::StrCat(
|
||||
internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
|
||||
|
|
@ -90,21 +91,15 @@ void SetMessageVariables(
|
|||
// ===================================================================
|
||||
|
||||
ImmutableMessageFieldGenerator::ImmutableMessageFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
|
||||
Context* context)
|
||||
: ImmutableFieldGenerator(descriptor, messageBitIndex, builderBitIndex,
|
||||
context) {
|
||||
SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
|
||||
const FieldDescriptor* descriptor, int bit_index, Context* context)
|
||||
: ImmutableFieldGenerator(descriptor, bit_index, context) {
|
||||
SetMessageVariables(descriptor, bit_index,
|
||||
context->GetFieldGeneratorInfo(descriptor),
|
||||
name_resolver_, &variables_, context);
|
||||
}
|
||||
|
||||
ImmutableMessageFieldGenerator::~ImmutableMessageFieldGenerator() = default;
|
||||
|
||||
int ImmutableMessageFieldGenerator::GetNumBitsForMessage() const {
|
||||
return HasHasbit(descriptor_) ? 1 : 0;
|
||||
}
|
||||
|
||||
void ImmutableMessageFieldGenerator::GenerateInterfaceHasMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
|
||||
|
|
@ -126,7 +121,6 @@ void ImmutableMessageFieldGenerator::GenerateInterfaceGetOrBuilderMethod(
|
|||
variables_,
|
||||
"$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder();\n");
|
||||
}
|
||||
|
||||
void ImmutableMessageFieldGenerator::GenerateInterfaceMembers(
|
||||
io::Printer* printer) const {
|
||||
// TODO: In the future, consider having a method specific to the
|
||||
|
|
@ -145,7 +139,7 @@ void ImmutableMessageFieldGenerator::GenerateHasMethod(
|
|||
printer->Print(variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
|
||||
" return $is_field_present_message$;\n"
|
||||
" return $is_field_present$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
|
@ -224,7 +218,7 @@ void ImmutableMessageFieldGenerator::GenerateBuilderHasMethod(
|
|||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
|
||||
" return $get_has_field_bit_builder$;\n"
|
||||
" return $get_has_field_bit$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
|
@ -253,7 +247,7 @@ void ImmutableMessageFieldGenerator::GenerateBuilderSetMethod(
|
|||
|
||||
"$name$Builder_.setMessage(value);\n",
|
||||
|
||||
"$set_has_field_bit_builder$\n"
|
||||
"$set_has_field_bit$\n"
|
||||
"$on_changed$\n"
|
||||
"return this;\n",
|
||||
Semantic::kSet);
|
||||
|
|
@ -279,7 +273,7 @@ void ImmutableMessageFieldGenerator::GenerateBuilderMergeMethod(
|
|||
PrintNestedBuilderFunction(
|
||||
printer,
|
||||
"$deprecation$public Builder ${$merge$capitalized_name$$}$($type$ value)",
|
||||
"if ($get_has_field_bit_builder$ &&\n"
|
||||
"if ($get_has_field_bit$ &&\n"
|
||||
" $name$_ != null &&\n"
|
||||
" $name$_ != $type$.getDefaultInstance()) {\n"
|
||||
" get$capitalized_name$Builder().mergeFrom(value);\n"
|
||||
|
|
@ -290,7 +284,7 @@ void ImmutableMessageFieldGenerator::GenerateBuilderMergeMethod(
|
|||
"$name$Builder_.mergeFrom(value);\n",
|
||||
|
||||
"if ($name$_ != null) {\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
"}\n"
|
||||
"return this;\n",
|
||||
|
|
@ -304,7 +298,7 @@ void ImmutableMessageFieldGenerator::GenerateBuilderClearMethod(
|
|||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
|
||||
" $clear_has_field_bit_builder$\n"
|
||||
" $clear_has_field_bit$\n"
|
||||
" $name$_ = null;\n"
|
||||
" if ($name$Builder_ != null) {\n"
|
||||
" $name$Builder_.dispose();\n"
|
||||
|
|
@ -323,7 +317,7 @@ void ImmutableMessageFieldGenerator::GenerateBuilderGetBuilderMethod(
|
|||
printer->Print(variables_,
|
||||
"$deprecation$public $type$.Builder "
|
||||
"${$get$capitalized_name$Builder$}$() {\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
" return "
|
||||
"internalGet$capitalized_name$FieldBuilder().getBuilder();\n"
|
||||
|
|
@ -392,7 +386,7 @@ void ImmutableMessageFieldGenerator::GenerateBuilderParseMethod(
|
|||
" $name$_ = input.readGroup($number$, $type$.parser(),\n"
|
||||
" extensionRegistry);\n"
|
||||
"}\n"
|
||||
"$set_has_field_bit_builder$\n");
|
||||
"$set_has_field_bit$\n");
|
||||
} else {
|
||||
printer->Print(
|
||||
variables_,
|
||||
|
|
@ -404,7 +398,7 @@ void ImmutableMessageFieldGenerator::GenerateBuilderParseMethod(
|
|||
"} else {\n"
|
||||
" $name$_ = input.readMessage($type$.parser(), extensionRegistry);\n"
|
||||
"}\n"
|
||||
"$set_has_field_bit_builder$\n");
|
||||
"$set_has_field_bit$\n");
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
|
|
@ -470,7 +464,7 @@ void ImmutableMessageFieldGenerator::GenerateBuildingCode(
|
|||
" result.$name$_ = $name$Builder_ == null\n"
|
||||
" ? $name$_\n"
|
||||
" : $name$Builder_.build();\n");
|
||||
if (GetNumBitsForMessage() > 0) {
|
||||
if (GetNumBits() > 0) {
|
||||
printer->Print(variables_, " $set_has_field_bit_to_local$;\n");
|
||||
}
|
||||
printer->Print("}\n");
|
||||
|
|
@ -486,7 +480,7 @@ void ImmutableMessageFieldGenerator::GenerateSerializationCode(
|
|||
io::Printer* printer) const {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"if ($is_field_present_message$) {\n"
|
||||
"if ($is_field_present$) {\n"
|
||||
" output.write$group_or_message$($number$, get$capitalized_name$());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
|
@ -495,7 +489,7 @@ void ImmutableMessageFieldGenerator::GenerateSerializedSizeCode(
|
|||
io::Printer* printer) const {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"if ($is_field_present_message$) {\n"
|
||||
"if ($is_field_present$) {\n"
|
||||
" size += com.google.protobuf.CodedOutputStream\n"
|
||||
" .compute$group_or_message$Size($number$, get$capitalized_name$());\n"
|
||||
"}\n");
|
||||
|
|
@ -522,10 +516,8 @@ std::string ImmutableMessageFieldGenerator::GetBoxedType() const {
|
|||
// ===================================================================
|
||||
|
||||
ImmutableMessageOneofFieldGenerator::ImmutableMessageOneofFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
|
||||
Context* context)
|
||||
: ImmutableMessageFieldGenerator(descriptor, messageBitIndex,
|
||||
builderBitIndex, context) {
|
||||
const FieldDescriptor* descriptor, int bit_index, Context* context)
|
||||
: ImmutableMessageFieldGenerator(descriptor, bit_index, context) {
|
||||
const OneofGeneratorInfo* info =
|
||||
context->GetOneofGeneratorInfo(descriptor->containing_oneof());
|
||||
SetCommonOneofVariables(descriptor, info, &variables_);
|
||||
|
|
@ -850,18 +842,12 @@ void ImmutableMessageOneofFieldGenerator::GenerateSerializedSizeCode(
|
|||
// ===================================================================
|
||||
|
||||
RepeatedImmutableMessageFieldGenerator::RepeatedImmutableMessageFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
|
||||
Context* context)
|
||||
: ImmutableMessageFieldGenerator(descriptor, messageBitIndex,
|
||||
builderBitIndex, context) {}
|
||||
const FieldDescriptor* descriptor, int bit_index, Context* context)
|
||||
: ImmutableMessageFieldGenerator(descriptor, bit_index, context) {}
|
||||
|
||||
RepeatedImmutableMessageFieldGenerator::
|
||||
~RepeatedImmutableMessageFieldGenerator() = default;
|
||||
|
||||
int RepeatedImmutableMessageFieldGenerator::GetNumBitsForMessage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RepeatedImmutableMessageFieldGenerator::GenerateInterfaceGetListMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldDocComment(printer, descriptor_, context_->options());
|
||||
|
|
|
|||
|
|
@ -37,9 +37,7 @@ namespace java {
|
|||
class ImmutableMessageFieldGenerator : public ImmutableFieldGenerator {
|
||||
public:
|
||||
explicit ImmutableMessageFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex,
|
||||
int builderBitIndex,
|
||||
Context* context);
|
||||
int bit_index, Context* context);
|
||||
ImmutableMessageFieldGenerator(const ImmutableMessageFieldGenerator&) =
|
||||
delete;
|
||||
ImmutableMessageFieldGenerator& operator=(
|
||||
|
|
@ -48,7 +46,7 @@ class ImmutableMessageFieldGenerator : public ImmutableFieldGenerator {
|
|||
|
||||
// implements ImmutableFieldGenerator
|
||||
// ---------------------------------------
|
||||
int GetNumBitsForMessage() const override;
|
||||
|
||||
void GenerateInterfaceMembers(io::Printer* printer) const override;
|
||||
void GenerateMembers(io::Printer* printer) const override;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const override;
|
||||
|
|
@ -102,8 +100,7 @@ class ImmutableMessageOneofFieldGenerator
|
|||
: public ImmutableMessageFieldGenerator {
|
||||
public:
|
||||
ImmutableMessageOneofFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex, int builderBitIndex,
|
||||
Context* context);
|
||||
int bit_index, Context* context);
|
||||
ImmutableMessageOneofFieldGenerator(
|
||||
const ImmutableMessageOneofFieldGenerator&) = delete;
|
||||
ImmutableMessageOneofFieldGenerator& operator=(
|
||||
|
|
@ -139,8 +136,7 @@ class RepeatedImmutableMessageFieldGenerator
|
|||
: public ImmutableMessageFieldGenerator {
|
||||
public:
|
||||
explicit RepeatedImmutableMessageFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int messageBitIndex,
|
||||
int builderBitIndex, Context* context);
|
||||
const FieldDescriptor* descriptor, int bit_index, Context* context);
|
||||
RepeatedImmutableMessageFieldGenerator(
|
||||
const RepeatedImmutableMessageFieldGenerator&) = delete;
|
||||
RepeatedImmutableMessageFieldGenerator& operator=(
|
||||
|
|
@ -148,7 +144,6 @@ class RepeatedImmutableMessageFieldGenerator
|
|||
~RepeatedImmutableMessageFieldGenerator() override;
|
||||
|
||||
// implements ImmutableFieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const override;
|
||||
void GenerateInterfaceMembers(io::Printer* printer) const override;
|
||||
void GenerateMembers(io::Printer* printer) const override;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const override;
|
||||
|
|
|
|||
|
|
@ -59,9 +59,8 @@ void AddPrimitiveVariableForThisAndOther(
|
|||
}
|
||||
|
||||
void SetPrimitiveVariables(
|
||||
const FieldDescriptor* descriptor, int message_bit_index,
|
||||
int builder_bit_index, const FieldGeneratorInfo* info,
|
||||
ClassNameResolver* name_resolver,
|
||||
const FieldDescriptor* descriptor, int bit_index,
|
||||
const FieldGeneratorInfo* info, ClassNameResolver* name_resolver,
|
||||
absl::flat_hash_map<absl::string_view, std::string>* variables,
|
||||
Context* context) {
|
||||
SetCommonFieldVariables(descriptor, info, variables);
|
||||
|
|
@ -131,17 +130,16 @@ void SetPrimitiveVariables(
|
|||
// For singular messages and builders, one bit is used for the hasField bit.
|
||||
// Note that these have a trailing ";".
|
||||
(*variables)["set_has_field_bit_to_local"] =
|
||||
absl::StrCat(GenerateSetBitToLocal(message_bit_index), ";");
|
||||
(*variables)["is_field_present_message"] =
|
||||
GenerateGetBit(message_bit_index);
|
||||
(*variables)["is_other_field_present_message"] =
|
||||
absl::StrCat(GenerateSetBitToLocal(bit_index), ";");
|
||||
(*variables)["is_field_present"] = GenerateGetBit(bit_index);
|
||||
(*variables)["is_other_field_present"] =
|
||||
absl::StrCat("other.has", (*variables)["capitalized_name"], "()");
|
||||
} else {
|
||||
(*variables)["set_has_field_bit_to_local"] = "";
|
||||
switch (descriptor->type()) {
|
||||
case FieldDescriptor::TYPE_BYTES:
|
||||
AddPrimitiveVariableForThisAndOther(
|
||||
"is_field_present_message", "is_other_field_present_message",
|
||||
"is_field_present", "is_other_field_present",
|
||||
[](absl::string_view value) {
|
||||
return absl::StrCat("!", value, ".isEmpty()");
|
||||
},
|
||||
|
|
@ -149,7 +147,7 @@ void SetPrimitiveVariables(
|
|||
break;
|
||||
case FieldDescriptor::TYPE_FLOAT:
|
||||
AddPrimitiveVariableForThisAndOther(
|
||||
"is_field_present_message", "is_other_field_present_message",
|
||||
"is_field_present", "is_other_field_present",
|
||||
[](absl::string_view value) {
|
||||
return absl::StrCat("java.lang.Float.floatToRawIntBits(", value,
|
||||
") != 0");
|
||||
|
|
@ -158,7 +156,7 @@ void SetPrimitiveVariables(
|
|||
break;
|
||||
case FieldDescriptor::TYPE_DOUBLE:
|
||||
AddPrimitiveVariableForThisAndOther(
|
||||
"is_field_present_message", "is_other_field_present_message",
|
||||
"is_field_present", "is_other_field_present",
|
||||
[](absl::string_view value) {
|
||||
return absl::StrCat("java.lang.Double.doubleToRawLongBits(",
|
||||
value, ") != 0");
|
||||
|
|
@ -167,7 +165,7 @@ void SetPrimitiveVariables(
|
|||
break;
|
||||
default:
|
||||
AddPrimitiveVariableForThisAndOther(
|
||||
"is_field_present_message", "is_other_field_present_message",
|
||||
"is_field_present", "is_other_field_present",
|
||||
[variables](absl::string_view value) {
|
||||
return absl::StrCat(value, " != ", (*variables)["default"]);
|
||||
},
|
||||
|
|
@ -178,13 +176,13 @@ void SetPrimitiveVariables(
|
|||
|
||||
// Always track the presence of a field explicitly in the builder, regardless
|
||||
// of syntax.
|
||||
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builder_bit_index);
|
||||
(*variables)["get_has_field_bit"] = GenerateGetBit(bit_index);
|
||||
(*variables)["get_has_field_bit_from_local"] =
|
||||
GenerateGetBitFromLocal(builder_bit_index);
|
||||
(*variables)["set_has_field_bit_builder"] =
|
||||
absl::StrCat(GenerateSetBit(builder_bit_index), ";");
|
||||
(*variables)["clear_has_field_bit_builder"] =
|
||||
absl::StrCat(GenerateClearBit(builder_bit_index), ";");
|
||||
GenerateGetBitFromLocal(bit_index);
|
||||
(*variables)["set_has_field_bit"] =
|
||||
absl::StrCat(GenerateSetBit(bit_index), ";");
|
||||
(*variables)["clear_has_field_bit"] =
|
||||
absl::StrCat(GenerateClearBit(bit_index), ";");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -192,21 +190,16 @@ void SetPrimitiveVariables(
|
|||
// ===================================================================
|
||||
|
||||
ImmutablePrimitiveFieldGenerator::ImmutablePrimitiveFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int message_bit_index,
|
||||
int builder_bit_index, Context* context)
|
||||
: ImmutableFieldGenerator(descriptor, message_bit_index, builder_bit_index,
|
||||
context) {
|
||||
SetPrimitiveVariables(descriptor, message_bit_index, builder_bit_index,
|
||||
const FieldDescriptor* descriptor, int bit_index, Context* context)
|
||||
: ImmutableFieldGenerator(descriptor, bit_index, context) {
|
||||
SetPrimitiveVariables(descriptor, bit_index,
|
||||
context->GetFieldGeneratorInfo(descriptor),
|
||||
name_resolver_, &variables_, context);
|
||||
}
|
||||
|
||||
ImmutablePrimitiveFieldGenerator::~ImmutablePrimitiveFieldGenerator() = default;
|
||||
|
||||
int ImmutablePrimitiveFieldGenerator::GetNumBitsForMessage() const {
|
||||
return HasHasbit(descriptor_) ? 1 : 0;
|
||||
}
|
||||
void ImmutablePrimitiveFieldGenerator::GenerateInterfaceMembers(
|
||||
void ImmutablePrimitiveFieldGenerator::GenerateInterfaceHasMethod(
|
||||
io::Printer* printer) const {
|
||||
if (descriptor_->has_presence()) {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
|
||||
|
|
@ -214,15 +207,58 @@ void ImmutablePrimitiveFieldGenerator::GenerateInterfaceMembers(
|
|||
printer->Print(variables_,
|
||||
"$deprecation$boolean has$capitalized_name$();\n");
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveFieldGenerator::GenerateInterfaceGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n");
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveFieldGenerator::GenerateInterfaceMembers(
|
||||
io::Printer* printer) const {
|
||||
GenerateInterfaceHasMethod(printer);
|
||||
GenerateInterfaceGetMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveFieldGenerator::GenerateHasMethod(
|
||||
io::Printer* printer) const {
|
||||
if (descriptor_->has_presence()) {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
|
||||
" return $is_field_present$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveFieldGenerator::GenerateGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveFieldGenerator::GenerateMembers(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(variables_, "private $field_type$ $name$_ = $default$;\n");
|
||||
PrintExtraFieldInfo(variables_, printer);
|
||||
GenerateHasMethod(printer);
|
||||
GenerateGetMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveFieldGenerator::GenerateBuilderHasMethod(
|
||||
io::Printer* printer) const {
|
||||
if (descriptor_->has_presence()) {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
|
||||
context_->options());
|
||||
|
|
@ -230,11 +266,14 @@ void ImmutablePrimitiveFieldGenerator::GenerateMembers(
|
|||
variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
|
||||
" return $is_field_present_message$;\n"
|
||||
" return $get_has_field_bit$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveFieldGenerator::GenerateBuilderGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
|
|
@ -245,31 +284,8 @@ void ImmutablePrimitiveFieldGenerator::GenerateMembers(
|
|||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
|
||||
void ImmutablePrimitiveFieldGenerator::GenerateBuilderSetMethod(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(variables_, "private $field_type$ $name$_ $default_init$;\n");
|
||||
|
||||
if (descriptor_->has_presence()) {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
|
||||
" return $get_has_field_bit_builder$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public $type$ ${$get$capitalized_name$$}$() {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -278,19 +294,22 @@ void ImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
|
|||
"${$set$capitalized_name$$}$($type$ value) {\n"
|
||||
" $null_check$\n"
|
||||
" $name$_ = value;\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveFieldGenerator::GenerateBuilderClearMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
|
||||
" $clear_has_field_bit_builder$\n");
|
||||
" $clear_has_field_bit$\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
JavaType type = GetJavaType(descriptor_);
|
||||
if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) {
|
||||
|
|
@ -308,6 +327,15 @@ void ImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
|
|||
"}\n");
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(variables_, "private $field_type$ $name$_ $default_init$;\n");
|
||||
GenerateBuilderHasMethod(printer);
|
||||
GenerateBuilderGetMethod(printer);
|
||||
GenerateBuilderSetMethod(printer);
|
||||
GenerateBuilderClearMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveFieldGenerator::GenerateFieldBuilderInitializationCode(
|
||||
io::Printer* printer) const {
|
||||
// noop for primitives
|
||||
|
|
@ -329,7 +357,7 @@ void ImmutablePrimitiveFieldGenerator::GenerateBuilderClearCode(
|
|||
void ImmutablePrimitiveFieldGenerator::GenerateMergingCode(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($is_other_field_present_message$) {\n"
|
||||
"if ($is_other_field_present$) {\n"
|
||||
" set$capitalized_name$(other.get$capitalized_name$());\n"
|
||||
"}\n");
|
||||
}
|
||||
|
|
@ -339,7 +367,7 @@ void ImmutablePrimitiveFieldGenerator::GenerateBuildingCode(
|
|||
printer->Print(variables_,
|
||||
"if ($get_has_field_bit_from_local$) {\n"
|
||||
" result.$name$_ = $name$_;\n");
|
||||
if (GetNumBitsForMessage() > 0) {
|
||||
if (GetNumBits() > 0) {
|
||||
printer->Print(variables_, " $set_has_field_bit_to_local$\n");
|
||||
}
|
||||
printer->Print("}\n");
|
||||
|
|
@ -349,13 +377,13 @@ void ImmutablePrimitiveFieldGenerator::GenerateBuilderParsingCode(
|
|||
io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"$name$_ = input.read$capitalized_type$();\n"
|
||||
"$set_has_field_bit_builder$\n");
|
||||
"$set_has_field_bit$\n");
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveFieldGenerator::GenerateSerializationCode(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($is_field_present_message$) {\n"
|
||||
"if ($is_field_present$) {\n"
|
||||
" output.write$capitalized_type$($number$, $name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
|
@ -363,7 +391,7 @@ void ImmutablePrimitiveFieldGenerator::GenerateSerializationCode(
|
|||
void ImmutablePrimitiveFieldGenerator::GenerateSerializedSizeCode(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($is_field_present_message$) {\n"
|
||||
"if ($is_field_present$) {\n"
|
||||
" size += com.google.protobuf.CodedOutputStream\n"
|
||||
" .compute$capitalized_type$Size($number$, $name$_);\n"
|
||||
"}\n");
|
||||
|
|
@ -470,10 +498,8 @@ std::string ImmutablePrimitiveFieldGenerator::GetBoxedType() const {
|
|||
// ===================================================================
|
||||
|
||||
ImmutablePrimitiveOneofFieldGenerator::ImmutablePrimitiveOneofFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int message_bit_index,
|
||||
int builder_bit_index, Context* context)
|
||||
: ImmutablePrimitiveFieldGenerator(descriptor, message_bit_index,
|
||||
builder_bit_index, context) {
|
||||
const FieldDescriptor* descriptor, int bit_index, Context* context)
|
||||
: ImmutablePrimitiveFieldGenerator(descriptor, bit_index, context) {
|
||||
const OneofGeneratorInfo* info =
|
||||
context->GetOneofGeneratorInfo(descriptor->containing_oneof());
|
||||
SetCommonOneofVariables(descriptor, info, &variables_);
|
||||
|
|
@ -482,9 +508,8 @@ ImmutablePrimitiveOneofFieldGenerator::ImmutablePrimitiveOneofFieldGenerator(
|
|||
ImmutablePrimitiveOneofFieldGenerator::
|
||||
~ImmutablePrimitiveOneofFieldGenerator() = default;
|
||||
|
||||
void ImmutablePrimitiveOneofFieldGenerator::GenerateMembers(
|
||||
void ImmutablePrimitiveOneofFieldGenerator::GenerateHasMethod(
|
||||
io::Printer* printer) const {
|
||||
PrintExtraFieldInfo(variables_, printer);
|
||||
ABSL_DCHECK(descriptor_->has_presence());
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
|
||||
context_->options());
|
||||
|
|
@ -494,7 +519,10 @@ void ImmutablePrimitiveOneofFieldGenerator::GenerateMembers(
|
|||
" return $has_oneof_case_message$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveOneofFieldGenerator::GenerateGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
|
|
@ -508,7 +536,14 @@ void ImmutablePrimitiveOneofFieldGenerator::GenerateMembers(
|
|||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderMembers(
|
||||
void ImmutablePrimitiveOneofFieldGenerator::GenerateMembers(
|
||||
io::Printer* printer) const {
|
||||
PrintExtraFieldInfo(variables_, printer);
|
||||
GenerateHasMethod(printer);
|
||||
GenerateGetMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderHasMethod(
|
||||
io::Printer* printer) const {
|
||||
ABSL_DCHECK(descriptor_->has_presence());
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
|
||||
|
|
@ -518,7 +553,10 @@ void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderMembers(
|
|||
" return $has_oneof_case_message$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
|
|
@ -529,7 +567,10 @@ void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderMembers(
|
|||
" return $default$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderSetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -543,7 +584,10 @@ void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderMembers(
|
|||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderClearMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -560,6 +604,14 @@ void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderMembers(
|
|||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderMembers(
|
||||
io::Printer* printer) const {
|
||||
GenerateBuilderHasMethod(printer);
|
||||
GenerateBuilderGetMethod(printer);
|
||||
GenerateBuilderSetMethod(printer);
|
||||
GenerateBuilderClearMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderClearCode(
|
||||
io::Printer* printer) const {
|
||||
// No-Op: When a primitive field is in a oneof, clearing the oneof clears that
|
||||
|
|
@ -623,36 +675,81 @@ void ImmutablePrimitiveOneofFieldGenerator::GenerateSerializedSizeCode(
|
|||
|
||||
RepeatedImmutablePrimitiveFieldGenerator::
|
||||
RepeatedImmutablePrimitiveFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int message_bit_index,
|
||||
int builder_bit_index,
|
||||
Context* context)
|
||||
: ImmutablePrimitiveFieldGenerator(descriptor, message_bit_index,
|
||||
builder_bit_index, context) {}
|
||||
int bit_index, Context* context)
|
||||
: ImmutablePrimitiveFieldGenerator(descriptor, bit_index, context) {}
|
||||
|
||||
RepeatedImmutablePrimitiveFieldGenerator::
|
||||
~RepeatedImmutablePrimitiveFieldGenerator() = default;
|
||||
|
||||
int RepeatedImmutablePrimitiveFieldGenerator::GetNumBitsForMessage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateInterfaceMembers(
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateInterfaceGetListMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$java.util.List<$boxed_type$> "
|
||||
"get$capitalized_name$List();\n");
|
||||
}
|
||||
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateInterfaceGetCountMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$int get$capitalized_name$Count();\n");
|
||||
}
|
||||
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateInterfaceGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$$type$ get$capitalized_name$(int index);\n");
|
||||
}
|
||||
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateInterfaceMembers(
|
||||
io::Printer* printer) const {
|
||||
GenerateInterfaceGetListMethod(printer);
|
||||
GenerateInterfaceGetCountMethod(printer);
|
||||
GenerateInterfaceGetMethod(printer);
|
||||
}
|
||||
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateGetListMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public java.util.List<$boxed_type$>\n"
|
||||
" ${$get$capitalized_name$List$}$() {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateGetCountMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
|
||||
" return $name$_.size();\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
|
||||
" return $repeated_get$(index);\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateMembers(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
|
|
@ -660,31 +757,9 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateMembers(
|
|||
"private $field_list_type$ $name$_ =\n"
|
||||
" $empty_list$;\n");
|
||||
PrintExtraFieldInfo(variables_, printer);
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public java.util.List<$boxed_type$>\n"
|
||||
" ${$get$capitalized_name$List$}$() {\n"
|
||||
" return $name$_;\n" // note: unmodifiable list
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
|
||||
" return $name$_.size();\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
|
||||
" return $repeated_get$(index);\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
GenerateGetListMethod(printer);
|
||||
GenerateGetCountMethod(printer);
|
||||
GenerateGetMethod(printer);
|
||||
|
||||
if (descriptor_->is_packed()) {
|
||||
printer->Print(variables_,
|
||||
|
|
@ -692,16 +767,8 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateMembers(
|
|||
}
|
||||
}
|
||||
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateEnsureIsMutableMethod(
|
||||
io::Printer* printer) const {
|
||||
// We use a ProtobufArrayList because it starts as a mutable list that can be
|
||||
// switched to immutable when references are handed out. This allows copy-free
|
||||
// sharing. A bit in the bitfield tracks whether there are any items in the
|
||||
// list. The presence bit allows us to skip work on blocks of 32 fields by
|
||||
// by checking if the entire bit-field int == 0 (none of the fields are
|
||||
// present).
|
||||
// We use one method and pass -1 when capacity is unknown to control class
|
||||
// size.
|
||||
printer->Print(
|
||||
variables_,
|
||||
"private $field_list_type$ $name$_ = $empty_list$;\n"
|
||||
|
|
@ -709,13 +776,12 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
|
|||
" if (!$name$_.isModifiable()) {\n"
|
||||
" $name$_ = makeMutableCopy($name$_, capacity);\n"
|
||||
" }\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
// Note: We return an unmodifiable list because otherwise the caller
|
||||
// could hold on to the returned list and modify it after the message
|
||||
// has been built, thus mutating the message which is supposed to be
|
||||
// immutable.
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderGetListMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
|
|
@ -725,6 +791,10 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
|
|||
" return $name$_;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderGetCountMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
|
|
@ -733,6 +803,10 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
|
|||
" return $name$_.size();\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
|
|
@ -741,6 +815,10 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
|
|||
" return $repeated_get$(index);\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderSetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -750,11 +828,15 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
|
|||
" $null_check$\n"
|
||||
" ensure$capitalized_name$IsMutable(/* capacity= */ -1);\n"
|
||||
" $repeated_set$(index, value);\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderAddMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -764,11 +846,15 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
|
|||
" $null_check$\n"
|
||||
" ensure$capitalized_name$IsMutable(/* capacity= */ -1);\n"
|
||||
" $repeated_add$(value);\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderAddAllMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -778,11 +864,15 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
|
|||
" ensure$capitalized_name$IsMutable(/* capacity= */ -1);\n"
|
||||
" com.google.protobuf.AbstractMessageLite.Builder.addAll(\n"
|
||||
" values, $name$_);\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderClearMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -790,13 +880,25 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
|
|||
variables_,
|
||||
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
|
||||
" $name$_ = $empty_list$;\n"
|
||||
" $clear_has_field_bit_builder$\n"
|
||||
" $clear_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
|
||||
io::Printer* printer) const {
|
||||
GenerateEnsureIsMutableMethod(printer);
|
||||
GenerateBuilderGetListMethod(printer);
|
||||
GenerateBuilderGetCountMethod(printer);
|
||||
GenerateBuilderGetMethod(printer);
|
||||
GenerateBuilderSetMethod(printer);
|
||||
GenerateBuilderAddMethod(printer);
|
||||
GenerateBuilderAddAllMethod(printer);
|
||||
GenerateBuilderClearMethod(printer);
|
||||
}
|
||||
|
||||
void RepeatedImmutablePrimitiveFieldGenerator::
|
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
|
||||
// noop for primitives
|
||||
|
|
@ -824,7 +926,7 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateMergingCode(
|
|||
" if ($name$_.isEmpty()) {\n"
|
||||
" $name$_ = other.$name$_;\n"
|
||||
" $name_make_immutable$;\n"
|
||||
" $set_has_field_bit_builder$\n");
|
||||
" $set_has_field_bit$\n");
|
||||
printer->Print(variables_,
|
||||
" } else {\n"
|
||||
" ensure$capitalized_name$IsMutable(/* capacity= */ -1);\n"
|
||||
|
|
|
|||
|
|
@ -36,9 +36,7 @@ namespace java {
|
|||
class ImmutablePrimitiveFieldGenerator : public ImmutableFieldGenerator {
|
||||
public:
|
||||
explicit ImmutablePrimitiveFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int message_bit_index,
|
||||
int builder_bit_index,
|
||||
Context* context);
|
||||
int bit_index, Context* context);
|
||||
ImmutablePrimitiveFieldGenerator(const ImmutablePrimitiveFieldGenerator&) =
|
||||
delete;
|
||||
ImmutablePrimitiveFieldGenerator& operator=(
|
||||
|
|
@ -47,7 +45,7 @@ class ImmutablePrimitiveFieldGenerator : public ImmutableFieldGenerator {
|
|||
|
||||
// implements ImmutableFieldGenerator
|
||||
// ---------------------------------------
|
||||
int GetNumBitsForMessage() const override;
|
||||
|
||||
void GenerateInterfaceMembers(io::Printer* printer) const override;
|
||||
void GenerateMembers(io::Printer* printer) const override;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const override;
|
||||
|
|
@ -65,16 +63,24 @@ class ImmutablePrimitiveFieldGenerator : public ImmutableFieldGenerator {
|
|||
|
||||
std::string GetBoxedType() const override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
void GenerateInterfaceHasMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetMethod(io::Printer* printer) const;
|
||||
|
||||
void GenerateHasMethod(io::Printer* printer) const;
|
||||
void GenerateGetMethod(io::Printer* printer) const;
|
||||
|
||||
void GenerateBuilderHasMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderSetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderClearMethod(io::Printer* printer) const;
|
||||
};
|
||||
|
||||
class ImmutablePrimitiveOneofFieldGenerator
|
||||
: public ImmutablePrimitiveFieldGenerator {
|
||||
public:
|
||||
ImmutablePrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int message_bit_index,
|
||||
int builder_bit_index,
|
||||
Context* context);
|
||||
int bit_index, Context* context);
|
||||
ImmutablePrimitiveOneofFieldGenerator(
|
||||
const ImmutablePrimitiveOneofFieldGenerator&) = delete;
|
||||
ImmutablePrimitiveOneofFieldGenerator& operator=(
|
||||
|
|
@ -89,14 +95,22 @@ class ImmutablePrimitiveOneofFieldGenerator
|
|||
void GenerateBuilderParsingCode(io::Printer* printer) const override;
|
||||
void GenerateSerializationCode(io::Printer* printer) const override;
|
||||
void GenerateSerializedSizeCode(io::Printer* printer) const override;
|
||||
|
||||
private:
|
||||
void GenerateHasMethod(io::Printer* printer) const;
|
||||
void GenerateGetMethod(io::Printer* printer) const;
|
||||
|
||||
void GenerateBuilderHasMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderSetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderClearMethod(io::Printer* printer) const;
|
||||
};
|
||||
|
||||
class RepeatedImmutablePrimitiveFieldGenerator
|
||||
: public ImmutablePrimitiveFieldGenerator {
|
||||
public:
|
||||
explicit RepeatedImmutablePrimitiveFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int message_bit_index,
|
||||
int builder_bit_index, Context* context);
|
||||
const FieldDescriptor* descriptor, int bit_index, Context* context);
|
||||
RepeatedImmutablePrimitiveFieldGenerator(
|
||||
const RepeatedImmutablePrimitiveFieldGenerator&) = delete;
|
||||
RepeatedImmutablePrimitiveFieldGenerator& operator=(
|
||||
|
|
@ -104,7 +118,6 @@ class RepeatedImmutablePrimitiveFieldGenerator
|
|||
~RepeatedImmutablePrimitiveFieldGenerator() override;
|
||||
|
||||
// implements ImmutableFieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const override;
|
||||
void GenerateInterfaceMembers(io::Printer* printer) const override;
|
||||
void GenerateMembers(io::Printer* printer) const override;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const override;
|
||||
|
|
@ -123,6 +136,24 @@ class RepeatedImmutablePrimitiveFieldGenerator
|
|||
void GenerateHashCode(io::Printer* printer) const override;
|
||||
|
||||
std::string GetBoxedType() const override;
|
||||
|
||||
private:
|
||||
void GenerateInterfaceGetListMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetCountMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetMethod(io::Printer* printer) const;
|
||||
|
||||
void GenerateGetListMethod(io::Printer* printer) const;
|
||||
void GenerateGetCountMethod(io::Printer* printer) const;
|
||||
void GenerateGetMethod(io::Printer* printer) const;
|
||||
|
||||
void GenerateEnsureIsMutableMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetListMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetCountMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderSetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderAddMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderAddAllMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderClearMethod(io::Printer* printer) const;
|
||||
};
|
||||
|
||||
} // namespace java
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
|
|||
namespace {
|
||||
|
||||
void SetPrimitiveVariables(
|
||||
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
|
||||
const FieldDescriptor* descriptor, int bit_index,
|
||||
const FieldGeneratorInfo* info, ClassNameResolver* name_resolver,
|
||||
absl::flat_hash_map<absl::string_view, std::string>* variables,
|
||||
Context* context) {
|
||||
|
|
@ -75,29 +75,24 @@ void SetPrimitiveVariables(
|
|||
if (HasHasbit(descriptor)) {
|
||||
// For singular messages and builders, one bit is used for the hasField bit.
|
||||
(*variables)["set_has_field_bit_to_local"] =
|
||||
GenerateSetBitToLocal(messageBitIndex);
|
||||
GenerateSetBitToLocal(bit_index);
|
||||
|
||||
// Note that these have a trailing ";".
|
||||
(*variables)["set_has_field_bit_message"] =
|
||||
absl::StrCat(GenerateSetBit(messageBitIndex), ";");
|
||||
|
||||
(*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
|
||||
(*variables)["is_field_present"] = GenerateGetBit(bit_index);
|
||||
} else {
|
||||
(*variables)["set_has_field_bit_to_local"] = "";
|
||||
(*variables)["set_has_field_bit_message"] = "";
|
||||
|
||||
variables->insert({"is_field_present_message",
|
||||
absl::StrCat("!", (*variables)["isStringEmpty"], "(",
|
||||
(*variables)["name"], "_)")});
|
||||
variables->insert(
|
||||
{"is_field_present", absl::StrCat("!", (*variables)["isStringEmpty"],
|
||||
"(", (*variables)["name"], "_)")});
|
||||
}
|
||||
|
||||
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
|
||||
(*variables)["get_has_field_bit"] = GenerateGetBit(bit_index);
|
||||
(*variables)["get_has_field_bit_from_local"] =
|
||||
GenerateGetBitFromLocal(builderBitIndex);
|
||||
(*variables)["set_has_field_bit_builder"] =
|
||||
absl::StrCat(GenerateSetBit(builderBitIndex), ";");
|
||||
(*variables)["clear_has_field_bit_builder"] =
|
||||
absl::StrCat(GenerateClearBit(builderBitIndex), ";");
|
||||
GenerateGetBitFromLocal(bit_index);
|
||||
(*variables)["set_has_field_bit"] =
|
||||
absl::StrCat(GenerateSetBit(bit_index), ";");
|
||||
(*variables)["clear_has_field_bit"] =
|
||||
absl::StrCat(GenerateClearBit(bit_index), ";");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -105,20 +100,15 @@ void SetPrimitiveVariables(
|
|||
// ===================================================================
|
||||
|
||||
ImmutableStringFieldGenerator::ImmutableStringFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
|
||||
Context* context)
|
||||
: ImmutableFieldGenerator(descriptor, messageBitIndex, builderBitIndex,
|
||||
context) {
|
||||
SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
|
||||
const FieldDescriptor* descriptor, int bit_index, Context* context)
|
||||
: ImmutableFieldGenerator(descriptor, bit_index, context) {
|
||||
SetPrimitiveVariables(descriptor, bit_index,
|
||||
context->GetFieldGeneratorInfo(descriptor),
|
||||
name_resolver_, &variables_, context);
|
||||
}
|
||||
|
||||
ImmutableStringFieldGenerator::~ImmutableStringFieldGenerator() = default;
|
||||
|
||||
int ImmutableStringFieldGenerator::GetNumBitsForMessage() const {
|
||||
return HasHasbit(descriptor_) ? 1 : 0;
|
||||
}
|
||||
// A note about how strings are handled. This code used to just store a String
|
||||
// in the Message. This had two issues:
|
||||
//
|
||||
|
|
@ -150,7 +140,7 @@ int ImmutableStringFieldGenerator::GetNumBitsForMessage() const {
|
|||
//
|
||||
// For single fields, the logic for this is done inside the generated code. For
|
||||
// repeated fields, the logic is done in LazyStringArrayList.
|
||||
void ImmutableStringFieldGenerator::GenerateInterfaceMembers(
|
||||
void ImmutableStringFieldGenerator::GenerateInterfaceHasMethod(
|
||||
io::Printer* printer) const {
|
||||
if (descriptor_->has_presence()) {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
|
||||
|
|
@ -158,10 +148,18 @@ void ImmutableStringFieldGenerator::GenerateInterfaceMembers(
|
|||
printer->Print(variables_,
|
||||
"$deprecation$boolean has$capitalized_name$();\n");
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableStringFieldGenerator::GenerateInterfaceGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$java.lang.String get$capitalized_name$();\n");
|
||||
}
|
||||
|
||||
void ImmutableStringFieldGenerator::GenerateInterfaceGetBytesMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
|
|
@ -169,13 +167,15 @@ void ImmutableStringFieldGenerator::GenerateInterfaceMembers(
|
|||
" get$capitalized_name$Bytes();\n");
|
||||
}
|
||||
|
||||
void ImmutableStringFieldGenerator::GenerateMembers(
|
||||
void ImmutableStringFieldGenerator::GenerateInterfaceMembers(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"@SuppressWarnings(\"serial\")\n"
|
||||
"private volatile java.lang.Object $name$_ = $default$;\n");
|
||||
PrintExtraFieldInfo(variables_, printer);
|
||||
GenerateInterfaceHasMethod(printer);
|
||||
GenerateInterfaceGetMethod(printer);
|
||||
GenerateInterfaceGetBytesMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutableStringFieldGenerator::GenerateHasMethod(
|
||||
io::Printer* printer) const {
|
||||
if (descriptor_->has_presence()) {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
|
||||
context_->options());
|
||||
|
|
@ -183,11 +183,14 @@ void ImmutableStringFieldGenerator::GenerateMembers(
|
|||
variables_,
|
||||
"@java.lang.Override\n"
|
||||
"$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
|
||||
" return $is_field_present_message$;\n"
|
||||
" return $is_field_present$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableStringFieldGenerator::GenerateGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
|
|
@ -216,6 +219,10 @@ void ImmutableStringFieldGenerator::GenerateMembers(
|
|||
" return s;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void ImmutableStringFieldGenerator::GenerateGetBytesMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
|
|
@ -236,21 +243,33 @@ void ImmutableStringFieldGenerator::GenerateMembers(
|
|||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutableStringFieldGenerator::GenerateBuilderMembers(
|
||||
void ImmutableStringFieldGenerator::GenerateMembers(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private java.lang.Object $name$_ $default_init$;\n");
|
||||
"@SuppressWarnings(\"serial\")\n"
|
||||
"private volatile java.lang.Object $name$_ = $default$;\n");
|
||||
PrintExtraFieldInfo(variables_, printer);
|
||||
GenerateHasMethod(printer);
|
||||
GenerateGetMethod(printer);
|
||||
GenerateGetBytesMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutableStringFieldGenerator::GenerateBuilderHasMethod(
|
||||
io::Printer* printer) const {
|
||||
if (descriptor_->has_presence()) {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
|
||||
" return $get_has_field_bit_builder$;\n"
|
||||
" return $get_has_field_bit$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableStringFieldGenerator::GenerateBuilderGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
|
|
@ -276,7 +295,10 @@ void ImmutableStringFieldGenerator::GenerateBuilderMembers(
|
|||
" return (java.lang.String) ref;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void ImmutableStringFieldGenerator::GenerateBuilderGetBytesMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
|
|
@ -294,7 +316,10 @@ void ImmutableStringFieldGenerator::GenerateBuilderMembers(
|
|||
" }\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutableStringFieldGenerator::GenerateBuilderSetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -303,11 +328,15 @@ void ImmutableStringFieldGenerator::GenerateBuilderMembers(
|
|||
" java.lang.String value) {\n"
|
||||
" $null_check$\n"
|
||||
" $name$_ = value;\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void ImmutableStringFieldGenerator::GenerateBuilderClearMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -315,16 +344,17 @@ void ImmutableStringFieldGenerator::GenerateBuilderMembers(
|
|||
variables_,
|
||||
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
// The default value is not a simple literal so we want to avoid executing
|
||||
// it multiple times. Instead, get the default out of the default instance.
|
||||
printer->Print(variables_,
|
||||
" $name$_ = getDefaultInstance().get$capitalized_name$();\n");
|
||||
printer->Print(variables_,
|
||||
" $clear_has_field_bit_builder$\n"
|
||||
" $clear_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void ImmutableStringFieldGenerator::GenerateBuilderSetBytesMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -339,12 +369,24 @@ void ImmutableStringFieldGenerator::GenerateBuilderMembers(
|
|||
}
|
||||
printer->Print(variables_,
|
||||
" $name$_ = value;\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void ImmutableStringFieldGenerator::GenerateBuilderMembers(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private java.lang.Object $name$_ $default_init$;\n");
|
||||
GenerateBuilderHasMethod(printer);
|
||||
GenerateBuilderGetMethod(printer);
|
||||
GenerateBuilderGetBytesMethod(printer);
|
||||
GenerateBuilderSetMethod(printer);
|
||||
GenerateBuilderClearMethod(printer);
|
||||
GenerateBuilderSetBytesMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutableStringFieldGenerator::GenerateFieldBuilderInitializationCode(
|
||||
io::Printer* printer) const {
|
||||
// noop for primitives
|
||||
|
|
@ -368,14 +410,14 @@ void ImmutableStringFieldGenerator::GenerateMergingCode(
|
|||
printer->Print(variables_,
|
||||
"if (other.has$capitalized_name$()) {\n"
|
||||
" $name$_ = other.$name$_;\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
"}\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"if (!other.get$capitalized_name$().isEmpty()) {\n"
|
||||
" $name$_ = other.$name$_;\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
"}\n");
|
||||
}
|
||||
|
|
@ -386,7 +428,7 @@ void ImmutableStringFieldGenerator::GenerateBuildingCode(
|
|||
printer->Print(variables_,
|
||||
"if ($get_has_field_bit_from_local$) {\n"
|
||||
" result.$name$_ = $name$_;\n");
|
||||
if (GetNumBitsForMessage() > 0) {
|
||||
if (GetNumBits() > 0) {
|
||||
printer->Print(variables_, " $set_has_field_bit_to_local$;\n");
|
||||
}
|
||||
printer->Print("}\n");
|
||||
|
|
@ -398,18 +440,18 @@ void ImmutableStringFieldGenerator::GenerateBuilderParsingCode(
|
|||
printer->Print(variables_,
|
||||
"$name$_ = "
|
||||
"input.readStringRequireUtf8();\n"
|
||||
"$set_has_field_bit_builder$\n");
|
||||
"$set_has_field_bit$\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"$name$_ = input.readBytes();\n"
|
||||
"$set_has_field_bit_builder$\n");
|
||||
"$set_has_field_bit$\n");
|
||||
}
|
||||
}
|
||||
|
||||
void ImmutableStringFieldGenerator::GenerateSerializationCode(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($is_field_present_message$) {\n"
|
||||
"if ($is_field_present$) {\n"
|
||||
" $writeString$(output, $number$, $name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
|
@ -417,7 +459,7 @@ void ImmutableStringFieldGenerator::GenerateSerializationCode(
|
|||
void ImmutableStringFieldGenerator::GenerateSerializedSizeCode(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($is_field_present_message$) {\n"
|
||||
"if ($is_field_present$) {\n"
|
||||
" size += $computeStringSize$($number$, $name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
|
@ -443,10 +485,8 @@ std::string ImmutableStringFieldGenerator::GetBoxedType() const {
|
|||
// ===================================================================
|
||||
|
||||
ImmutableStringOneofFieldGenerator::ImmutableStringOneofFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
|
||||
Context* context)
|
||||
: ImmutableStringFieldGenerator(descriptor, messageBitIndex,
|
||||
builderBitIndex, context) {
|
||||
const FieldDescriptor* descriptor, int bit_index, Context* context)
|
||||
: ImmutableStringFieldGenerator(descriptor, bit_index, context) {
|
||||
const OneofGeneratorInfo* info =
|
||||
context->GetOneofGeneratorInfo(descriptor->containing_oneof());
|
||||
SetCommonOneofVariables(descriptor, info, &variables_);
|
||||
|
|
@ -455,9 +495,8 @@ ImmutableStringOneofFieldGenerator::ImmutableStringOneofFieldGenerator(
|
|||
ImmutableStringOneofFieldGenerator::~ImmutableStringOneofFieldGenerator() =
|
||||
default;
|
||||
|
||||
void ImmutableStringOneofFieldGenerator::GenerateMembers(
|
||||
void ImmutableStringOneofFieldGenerator::GenerateHasMethod(
|
||||
io::Printer* printer) const {
|
||||
PrintExtraFieldInfo(variables_, printer);
|
||||
ABSL_DCHECK(descriptor_->has_presence());
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
|
||||
context_->options());
|
||||
|
|
@ -466,7 +505,10 @@ void ImmutableStringOneofFieldGenerator::GenerateMembers(
|
|||
" return $has_oneof_case_message$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutableStringOneofFieldGenerator::GenerateGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
|
|
@ -495,6 +537,10 @@ void ImmutableStringOneofFieldGenerator::GenerateMembers(
|
|||
" return s;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void ImmutableStringOneofFieldGenerator::GenerateGetBytesMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
|
||||
|
|
@ -519,7 +565,15 @@ void ImmutableStringOneofFieldGenerator::GenerateMembers(
|
|||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
|
||||
void ImmutableStringOneofFieldGenerator::GenerateMembers(
|
||||
io::Printer* printer) const {
|
||||
PrintExtraFieldInfo(variables_, printer);
|
||||
GenerateHasMethod(printer);
|
||||
GenerateGetMethod(printer);
|
||||
GenerateGetBytesMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutableStringOneofFieldGenerator::GenerateBuilderHasMethod(
|
||||
io::Printer* printer) const {
|
||||
ABSL_DCHECK(descriptor_->has_presence());
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
|
||||
|
|
@ -530,7 +584,10 @@ void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
|
|||
" return $has_oneof_case_message$;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutableStringOneofFieldGenerator::GenerateBuilderGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
|
|
@ -560,7 +617,10 @@ void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
|
|||
" return (java.lang.String) ref;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void ImmutableStringOneofFieldGenerator::GenerateBuilderGetBytesMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldStringBytesAccessorDocComment(printer, descriptor_, GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
|
|
@ -583,7 +643,10 @@ void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
|
|||
" }\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void ImmutableStringOneofFieldGenerator::GenerateBuilderSetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, SETTER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -597,6 +660,10 @@ void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
|
|||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void ImmutableStringOneofFieldGenerator::GenerateBuilderClearMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -611,7 +678,10 @@ void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
|
|||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void ImmutableStringOneofFieldGenerator::GenerateBuilderSetBytesMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldStringBytesAccessorDocComment(printer, descriptor_, SETTER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -632,6 +702,16 @@ void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
|
|||
"}\n");
|
||||
}
|
||||
|
||||
void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
|
||||
io::Printer* printer) const {
|
||||
GenerateBuilderHasMethod(printer);
|
||||
GenerateBuilderGetMethod(printer);
|
||||
GenerateBuilderGetBytesMethod(printer);
|
||||
GenerateBuilderSetMethod(printer);
|
||||
GenerateBuilderClearMethod(printer);
|
||||
GenerateBuilderSetBytesMethod(printer);
|
||||
}
|
||||
|
||||
void ImmutableStringOneofFieldGenerator::GenerateBuilderClearCode(
|
||||
io::Printer* printer) const {
|
||||
// No-Op: String fields in oneofs are correctly cleared by clearing the oneof
|
||||
|
|
@ -687,41 +767,41 @@ void ImmutableStringOneofFieldGenerator::GenerateSerializedSizeCode(
|
|||
// ===================================================================
|
||||
|
||||
RepeatedImmutableStringFieldGenerator::RepeatedImmutableStringFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex,
|
||||
Context* context)
|
||||
: ImmutableStringFieldGenerator(descriptor, messageBitIndex,
|
||||
builderBitIndex, context) {}
|
||||
const FieldDescriptor* descriptor, int bit_index, Context* context)
|
||||
: ImmutableStringFieldGenerator(descriptor, bit_index, context) {}
|
||||
|
||||
RepeatedImmutableStringFieldGenerator::
|
||||
~RepeatedImmutableStringFieldGenerator() = default;
|
||||
|
||||
int RepeatedImmutableStringFieldGenerator::GetNumBitsForMessage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateInterfaceMembers(
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateInterfaceGetListMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
// NOTE: the same method in the implementation class actually returns
|
||||
// com.google.protobuf.ProtocolStringList (a subclass of List). It's
|
||||
// changed between protobuf 2.5.0 release and protobuf 2.6.1 release.
|
||||
// To retain binary compatibility with both 2.5.0 and 2.6.1 generated
|
||||
// code, we make this interface method return List so both methods
|
||||
// with different return types exist in the compiled byte code.
|
||||
"$deprecation$java.util.List<java.lang.String>\n"
|
||||
" get$capitalized_name$List();\n");
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateInterfaceGetCountMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$int get$capitalized_name$Count();\n");
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateInterfaceGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$java.lang.String get$capitalized_name$(int index);\n");
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateInterfaceGetBytesMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldStringBytesAccessorDocComment(
|
||||
printer, descriptor_, LIST_INDEXED_GETTER, context_->options());
|
||||
printer->Print(variables_,
|
||||
|
|
@ -729,6 +809,62 @@ void RepeatedImmutableStringFieldGenerator::GenerateInterfaceMembers(
|
|||
" get$capitalized_name$Bytes(int index);\n");
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateInterfaceMembers(
|
||||
io::Printer* printer) const {
|
||||
GenerateInterfaceGetListMethod(printer);
|
||||
GenerateInterfaceGetCountMethod(printer);
|
||||
GenerateInterfaceGetMethod(printer);
|
||||
GenerateInterfaceGetBytesMethod(printer);
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateGetListMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public com.google.protobuf.ProtocolStringList\n"
|
||||
" ${$get$capitalized_name$List$}$() {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateGetCountMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
|
||||
" return $name$_.size();\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public java.lang.String "
|
||||
"${$get$capitalized_name$$}$(int index) {\n"
|
||||
" return $name$_.get(index);\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateGetBytesMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldStringBytesAccessorDocComment(
|
||||
printer, descriptor_, LIST_INDEXED_GETTER, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public com.google.protobuf.ByteString\n"
|
||||
" ${$get$capitalized_name$Bytes$}$(int index) {\n"
|
||||
" return $name$_.getByteString(index);\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateMembers(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
|
|
@ -736,14 +872,39 @@ void RepeatedImmutableStringFieldGenerator::GenerateMembers(
|
|||
"private com.google.protobuf.LazyStringArrayList $name$_ =\n"
|
||||
" $empty_list$;\n");
|
||||
PrintExtraFieldInfo(variables_, printer);
|
||||
GenerateGetListMethod(printer);
|
||||
GenerateGetCountMethod(printer);
|
||||
GenerateGetMethod(printer);
|
||||
GenerateGetBytesMethod(printer);
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateEnsureIsMutableMethod(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"private void ensure$capitalized_name$IsMutable() {\n"
|
||||
" if (!$name$_.isModifiable()) {\n"
|
||||
" $name$_ = new com.google.protobuf.LazyStringArrayList($name$_);\n"
|
||||
" }\n"
|
||||
" $set_has_field_bit$\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateBuilderGetListMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public com.google.protobuf.ProtocolStringList\n"
|
||||
" ${$get$capitalized_name$List$}$() {\n"
|
||||
" return $name$_;\n" // note: unmodifiable list
|
||||
" $name$_.makeImmutable();\n"
|
||||
" return $name$_;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateBuilderGetCountMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
|
|
@ -752,6 +913,10 @@ void RepeatedImmutableStringFieldGenerator::GenerateMembers(
|
|||
" return $name$_.size();\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateBuilderGetMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
|
|
@ -760,6 +925,10 @@ void RepeatedImmutableStringFieldGenerator::GenerateMembers(
|
|||
" return $name$_.get(index);\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateBuilderGetBytesMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldStringBytesAccessorDocComment(
|
||||
printer, descriptor_, LIST_INDEXED_GETTER, context_->options());
|
||||
printer->Print(variables_,
|
||||
|
|
@ -770,67 +939,8 @@ void RepeatedImmutableStringFieldGenerator::GenerateMembers(
|
|||
printer->Annotate("{", "}", descriptor_);
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers(
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateBuilderSetMethod(
|
||||
io::Printer* printer) const {
|
||||
// One field is the list and the bit field keeps track of whether the
|
||||
// list is immutable. If it's immutable, the invariant is that it must
|
||||
// either an instance of Collections.emptyList() or it's an ArrayList
|
||||
// wrapped in a Collections.unmodifiableList() wrapper and nobody else has
|
||||
// a reference to the underlying ArrayList. This invariant allows us to
|
||||
// share instances of lists between protocol buffers avoiding expensive
|
||||
// memory allocations. Note, immutable is a strong guarantee here -- not
|
||||
// just that the list cannot be modified via the reference but that the
|
||||
// list can never be modified.
|
||||
printer->Print(variables_,
|
||||
"private com.google.protobuf.LazyStringArrayList $name$_ =\n"
|
||||
" $empty_list$;\n");
|
||||
|
||||
printer->Print(
|
||||
variables_,
|
||||
"private void ensure$capitalized_name$IsMutable() {\n"
|
||||
" if (!$name$_.isModifiable()) {\n"
|
||||
" $name$_ = new com.google.protobuf.LazyStringArrayList($name$_);\n"
|
||||
" }\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
"}\n");
|
||||
|
||||
// Note: We return an unmodifiable list because otherwise the caller
|
||||
// could hold on to the returned list and modify it after the message
|
||||
// has been built, thus mutating the message which is supposed to be
|
||||
// immutable.
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public com.google.protobuf.ProtocolStringList\n"
|
||||
" ${$get$capitalized_name$List$}$() {\n"
|
||||
" $name$_.makeImmutable();\n"
|
||||
" return $name$_;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
|
||||
context_->options());
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$deprecation$public int ${$get$capitalized_name$Count$}$() {\n"
|
||||
" return $name$_.size();\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER,
|
||||
context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public java.lang.String "
|
||||
"${$get$capitalized_name$$}$(int index) {\n"
|
||||
" return $name$_.get(index);\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
WriteFieldStringBytesAccessorDocComment(
|
||||
printer, descriptor_, LIST_INDEXED_GETTER, context_->options());
|
||||
printer->Print(variables_,
|
||||
"$deprecation$public com.google.protobuf.ByteString\n"
|
||||
" ${$get$capitalized_name$Bytes$}$(int index) {\n"
|
||||
" return $name$_.getByteString(index);\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_);
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -840,11 +950,15 @@ void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers(
|
|||
" $null_check$\n"
|
||||
" ensure$capitalized_name$IsMutable();\n"
|
||||
" $name$_.set(index, value);\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateBuilderAddMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -854,11 +968,15 @@ void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers(
|
|||
" $null_check$\n"
|
||||
" ensure$capitalized_name$IsMutable();\n"
|
||||
" $name$_.add(value);\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateBuilderAddAllMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -868,11 +986,15 @@ void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers(
|
|||
" ensure$capitalized_name$IsMutable();\n"
|
||||
" com.google.protobuf.AbstractMessageLite.Builder.addAll(\n"
|
||||
" values, $name$_);\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateBuilderClearMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -881,12 +1003,15 @@ void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers(
|
|||
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
|
||||
" $name$_ =\n"
|
||||
" $empty_list$;\n"
|
||||
" $clear_has_field_bit_builder$;\n"
|
||||
" $clear_has_field_bit$;\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateBuilderAddBytesMethod(
|
||||
io::Printer* printer) const {
|
||||
WriteFieldStringBytesAccessorDocComment(printer, descriptor_, LIST_ADDER,
|
||||
context_->options(),
|
||||
/* builder */ true);
|
||||
|
|
@ -902,12 +1027,29 @@ void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers(
|
|||
printer->Print(variables_,
|
||||
" ensure$capitalized_name$IsMutable();\n"
|
||||
" $name$_.add(value);\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" $on_changed$\n"
|
||||
" return this;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers(
|
||||
io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"private com.google.protobuf.LazyStringArrayList $name$_ =\n"
|
||||
" $empty_list$;\n");
|
||||
GenerateEnsureIsMutableMethod(printer);
|
||||
GenerateBuilderGetListMethod(printer);
|
||||
GenerateBuilderGetCountMethod(printer);
|
||||
GenerateBuilderGetMethod(printer);
|
||||
GenerateBuilderGetBytesMethod(printer);
|
||||
GenerateBuilderSetMethod(printer);
|
||||
GenerateBuilderAddMethod(printer);
|
||||
GenerateBuilderAddAllMethod(printer);
|
||||
GenerateBuilderClearMethod(printer);
|
||||
GenerateBuilderAddBytesMethod(printer);
|
||||
}
|
||||
|
||||
void RepeatedImmutableStringFieldGenerator::
|
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
|
||||
// noop for primitives
|
||||
|
|
@ -938,7 +1080,7 @@ void RepeatedImmutableStringFieldGenerator::GenerateMergingCode(
|
|||
"if (!other.$name$_.isEmpty()) {\n"
|
||||
" if ($name$_.isEmpty()) {\n"
|
||||
" $name$_ = other.$name$_;\n"
|
||||
" $set_has_field_bit_builder$\n"
|
||||
" $set_has_field_bit$\n"
|
||||
" } else {\n"
|
||||
" ensure$capitalized_name$IsMutable();\n"
|
||||
" $name$_.addAll(other.$name$_);\n"
|
||||
|
|
|
|||
|
|
@ -37,8 +37,7 @@ namespace java {
|
|||
class ImmutableStringFieldGenerator : public ImmutableFieldGenerator {
|
||||
public:
|
||||
explicit ImmutableStringFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex,
|
||||
int builderBitIndex, Context* context);
|
||||
int bit_index, Context* context);
|
||||
ImmutableStringFieldGenerator(const ImmutableStringFieldGenerator&) = delete;
|
||||
ImmutableStringFieldGenerator& operator=(
|
||||
const ImmutableStringFieldGenerator&) = delete;
|
||||
|
|
@ -46,7 +45,7 @@ class ImmutableStringFieldGenerator : public ImmutableFieldGenerator {
|
|||
|
||||
// implements ImmutableFieldGenerator
|
||||
// ---------------------------------------
|
||||
int GetNumBitsForMessage() const override;
|
||||
|
||||
void GenerateInterfaceMembers(io::Printer* printer) const override;
|
||||
void GenerateMembers(io::Printer* printer) const override;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const override;
|
||||
|
|
@ -64,22 +63,34 @@ class ImmutableStringFieldGenerator : public ImmutableFieldGenerator {
|
|||
|
||||
std::string GetBoxedType() const override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
void GenerateInterfaceHasMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetBytesMethod(io::Printer* printer) const;
|
||||
|
||||
void GenerateHasMethod(io::Printer* printer) const;
|
||||
void GenerateGetMethod(io::Printer* printer) const;
|
||||
void GenerateGetBytesMethod(io::Printer* printer) const;
|
||||
|
||||
void GenerateBuilderHasMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetBytesMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderSetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderClearMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderSetBytesMethod(io::Printer* printer) const;
|
||||
};
|
||||
|
||||
class ImmutableStringOneofFieldGenerator
|
||||
: public ImmutableStringFieldGenerator {
|
||||
public:
|
||||
ImmutableStringOneofFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int messageBitIndex, int builderBitIndex,
|
||||
Context* context);
|
||||
int bit_index, Context* context);
|
||||
ImmutableStringOneofFieldGenerator(
|
||||
const ImmutableStringOneofFieldGenerator&) = delete;
|
||||
ImmutableStringOneofFieldGenerator& operator=(
|
||||
const ImmutableStringOneofFieldGenerator&) = delete;
|
||||
~ImmutableStringOneofFieldGenerator() override;
|
||||
|
||||
private:
|
||||
void GenerateMembers(io::Printer* printer) const override;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const override;
|
||||
void GenerateBuilderClearCode(io::Printer* printer) const override;
|
||||
|
|
@ -88,14 +99,25 @@ class ImmutableStringOneofFieldGenerator
|
|||
void GenerateBuilderParsingCode(io::Printer* printer) const override;
|
||||
void GenerateSerializationCode(io::Printer* printer) const override;
|
||||
void GenerateSerializedSizeCode(io::Printer* printer) const override;
|
||||
|
||||
private:
|
||||
void GenerateHasMethod(io::Printer* printer) const;
|
||||
void GenerateGetMethod(io::Printer* printer) const;
|
||||
void GenerateGetBytesMethod(io::Printer* printer) const;
|
||||
|
||||
void GenerateBuilderHasMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetBytesMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderSetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderClearMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderSetBytesMethod(io::Printer* printer) const;
|
||||
};
|
||||
|
||||
class RepeatedImmutableStringFieldGenerator
|
||||
: public ImmutableStringFieldGenerator {
|
||||
public:
|
||||
explicit RepeatedImmutableStringFieldGenerator(
|
||||
const FieldDescriptor* descriptor, int messageBitIndex,
|
||||
int builderBitIndex, Context* context);
|
||||
const FieldDescriptor* descriptor, int bit_index, Context* context);
|
||||
RepeatedImmutableStringFieldGenerator(
|
||||
const RepeatedImmutableStringFieldGenerator&) = delete;
|
||||
RepeatedImmutableStringFieldGenerator& operator=(
|
||||
|
|
@ -103,7 +125,6 @@ class RepeatedImmutableStringFieldGenerator
|
|||
~RepeatedImmutableStringFieldGenerator() override;
|
||||
|
||||
// implements ImmutableFieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const override;
|
||||
void GenerateInterfaceMembers(io::Printer* printer) const override;
|
||||
void GenerateMembers(io::Printer* printer) const override;
|
||||
void GenerateBuilderMembers(io::Printer* printer) const override;
|
||||
|
|
@ -120,6 +141,28 @@ class RepeatedImmutableStringFieldGenerator
|
|||
void GenerateHashCode(io::Printer* printer) const override;
|
||||
|
||||
std::string GetBoxedType() const override;
|
||||
|
||||
private:
|
||||
void GenerateInterfaceGetListMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetCountMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetMethod(io::Printer* printer) const;
|
||||
void GenerateInterfaceGetBytesMethod(io::Printer* printer) const;
|
||||
|
||||
void GenerateGetListMethod(io::Printer* printer) const;
|
||||
void GenerateGetCountMethod(io::Printer* printer) const;
|
||||
void GenerateGetMethod(io::Printer* printer) const;
|
||||
void GenerateGetBytesMethod(io::Printer* printer) const;
|
||||
|
||||
void GenerateEnsureIsMutableMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetListMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetCountMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderGetBytesMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderSetMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderAddMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderAddAllMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderClearMethod(io::Printer* printer) const;
|
||||
void GenerateBuilderAddBytesMethod(io::Printer* printer) const;
|
||||
};
|
||||
|
||||
} // namespace java
|
||||
|
|
|
|||
|
|
@ -739,6 +739,9 @@ bool Parser::ParseSyntaxIdentifier(const FileDescriptorProto* file,
|
|||
|
||||
bool Parser::ParseTopLevelStatement(FileDescriptorProto* file,
|
||||
const LocationRecorder& root_location) {
|
||||
// Maximum depth allowed by the DescriptorPool.
|
||||
recursion_depth_ = internal::cpp::MaxMessageDeclarationNestingDepth();
|
||||
|
||||
if (TryConsumeEndOfDeclaration(";", nullptr)) {
|
||||
// empty statement; ignore
|
||||
return true;
|
||||
|
|
@ -753,8 +756,6 @@ bool Parser::ParseTopLevelStatement(FileDescriptorProto* file,
|
|||
LocationRecorder location(root_location,
|
||||
FileDescriptorProto::kMessageTypeFieldNumber,
|
||||
file->message_type_size());
|
||||
// Maximum depth allowed by the DescriptorPool.
|
||||
recursion_depth_ = internal::cpp::MaxMessageDeclarationNestingDepth();
|
||||
return ParseMessageDefinition(file->add_message_type(), visibility,
|
||||
location, file);
|
||||
} else if (LookingAt("enum")) {
|
||||
|
|
@ -1145,6 +1146,17 @@ bool Parser::ParseMessageFieldNoLabel(
|
|||
|
||||
field->set_type_name(group->name());
|
||||
if (LookingAt("{")) {
|
||||
const auto undo_depth = absl::MakeCleanup([&] {
|
||||
if (limit_group_nesting_) ++recursion_depth_;
|
||||
});
|
||||
|
||||
if (limit_group_nesting_) {
|
||||
if (--recursion_depth_ <= 0) {
|
||||
RecordError("Reached maximum recursion limit for nested messages.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DO(ParseMessageBlock(group, group_location, containing_file));
|
||||
} else {
|
||||
RecordError("Missing group body.");
|
||||
|
|
|
|||
|
|
@ -572,6 +572,7 @@ class PROTOBUF_EXPORT Parser final {
|
|||
SourceLocationTable* source_location_table_; // legacy
|
||||
bool had_errors_;
|
||||
bool require_syntax_identifier_;
|
||||
bool limit_group_nesting_ = false;
|
||||
bool stop_after_syntax_identifier_;
|
||||
std::string syntax_identifier_;
|
||||
Edition edition_ = Edition::EDITION_UNKNOWN;
|
||||
|
|
|
|||
|
|
@ -2293,6 +2293,54 @@ TEST_F(ParseErrorTest, NestingIsLimitedWithoutCrashing) {
|
|||
ExpectHasErrors(input(), error);
|
||||
}
|
||||
|
||||
TEST_F(ParseErrorTest, NestedMessagesInExtendGroupAreLimited) {
|
||||
std::string start =
|
||||
"syntax = \"proto2\";\n"
|
||||
"message Extendable { extensions 1 to max; }\n"
|
||||
"extend Extendable {\n"
|
||||
" optional group Ext = 1 {\n";
|
||||
std::string end = " }\n}\n";
|
||||
|
||||
const auto add = [&] {
|
||||
absl::StrAppend(&start, "message M {");
|
||||
absl::StrAppend(&end, "}");
|
||||
};
|
||||
const auto input = [&] { return absl::StrCat(start, end); };
|
||||
|
||||
// The first ones work correctly.
|
||||
// We test up to MaxMessageDeclarationNestingDepth() - 2 to be portable
|
||||
// between configurations (flag on/off, OSS/Google3).
|
||||
for (int i = 1; i < internal::cpp::MaxMessageDeclarationNestingDepth() - 1;
|
||||
++i) {
|
||||
add();
|
||||
const std::string str = input();
|
||||
SetupParser(str);
|
||||
FileDescriptorProto proto;
|
||||
proto.set_name("foo.proto");
|
||||
EXPECT_TRUE(parser_->Parse(input_.get(), &proto)) << input();
|
||||
EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
|
||||
ASSERT_EQ("", error_collector_.text_);
|
||||
DescriptorPool pool;
|
||||
ASSERT_TRUE(pool.BuildFile(proto));
|
||||
}
|
||||
|
||||
// The rest have parsing errors but they don't crash no matter how deep we
|
||||
// make them.
|
||||
const auto error = testing::HasSubstr(
|
||||
"Reached maximum recursion limit for nested messages.");
|
||||
|
||||
// Add enough levels to trigger error in all configurations.
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
add();
|
||||
}
|
||||
ExpectHasErrors(input(), error);
|
||||
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
add();
|
||||
}
|
||||
ExpectHasErrors(input(), error);
|
||||
}
|
||||
|
||||
TEST_F(ParseErrorTest, MissingFieldNumber) {
|
||||
ExpectHasErrors(
|
||||
"message TestMessage {\n"
|
||||
|
|
|
|||
|
|
@ -27,6 +27,22 @@ cc_binary(
|
|||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "names",
|
||||
srcs = ["names.cc"],
|
||||
hdrs = ["names.h"],
|
||||
copts = COPTS,
|
||||
strip_include_prefix = "/src",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//src/google/protobuf",
|
||||
"//src/google/protobuf:port",
|
||||
"//src/google/protobuf/compiler:code_generator",
|
||||
"@abseil-cpp//absl/log:absl_check",
|
||||
"@abseil-cpp//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "python",
|
||||
srcs = [
|
||||
|
|
@ -47,6 +63,7 @@ cc_library(
|
|||
"@com_github_grpc_grpc//tools/distrib/python/grpcio_tools:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":names",
|
||||
"//src/google/protobuf",
|
||||
"//src/google/protobuf:port",
|
||||
"//src/google/protobuf/compiler:code_generator",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#include "absl/strings/substitute.h"
|
||||
#include "google/protobuf/compiler/code_generator.h"
|
||||
#include "google/protobuf/compiler/python/helpers.h"
|
||||
#include "google/protobuf/compiler/python/names.h"
|
||||
#include "google/protobuf/compiler/python/pyi_generator.h"
|
||||
#include "google/protobuf/compiler/retention.h"
|
||||
#include "google/protobuf/compiler/versions.h"
|
||||
|
|
@ -62,19 +63,6 @@ namespace compiler {
|
|||
namespace python {
|
||||
|
||||
namespace {
|
||||
// Returns the alias we assign to the module of the given .proto filename
|
||||
// when importing. See testPackageInitializationImport in
|
||||
// third_party/py/google/protobuf/internal/reflection_test.py
|
||||
// to see why we need the alias.
|
||||
std::string ModuleAlias(absl::string_view filename) {
|
||||
std::string module_name = ModuleName(filename);
|
||||
// We can't have dots in the module name, so we replace each with _dot_.
|
||||
// But that could lead to a collision between a.b and a_dot_b, so we also
|
||||
// duplicate each underscore.
|
||||
absl::StrReplaceAll({{"_", "__"}}, &module_name);
|
||||
absl::StrReplaceAll({{".", "_dot_"}}, &module_name);
|
||||
return module_name;
|
||||
}
|
||||
|
||||
// Name of the class attribute where we store the Python
|
||||
// descriptor.Descriptor instance for the generated class.
|
||||
|
|
@ -311,7 +299,7 @@ bool Generator::Generate(const FileDescriptor* file,
|
|||
if (GeneratingDescriptorProto()) {
|
||||
printer_->Outdent();
|
||||
}
|
||||
std::string module_name = ModuleName(file->name());
|
||||
std::string module_name = ModuleName(file);
|
||||
if (!opensource_runtime_) {
|
||||
module_name =
|
||||
std::string(absl::StripPrefix(module_name, kThirdPartyPrefix));
|
||||
|
|
@ -396,8 +384,8 @@ void Generator::PrintTopBoilerplate() const {
|
|||
printer_->Print("\n\n");
|
||||
}
|
||||
|
||||
std::string Generator::ImportModuleName(absl::string_view filename) const {
|
||||
std::string module_name = ModuleName(filename);
|
||||
std::string Generator::ImportModuleName(const FileDescriptor* file) const {
|
||||
std::string module_name = ModuleName(file);
|
||||
if (!opensource_runtime_) {
|
||||
module_name =
|
||||
std::string(absl::StripPrefix(module_name, kThirdPartyPrefix));
|
||||
|
|
@ -409,10 +397,8 @@ std::string Generator::ImportModuleName(absl::string_view filename) const {
|
|||
void Generator::PrintImports() const {
|
||||
bool has_importlib = false;
|
||||
for (int i = 0; i < file_->dependency_count(); ++i) {
|
||||
absl::string_view filename = file_->dependency(i)->name();
|
||||
|
||||
std::string module_name = ImportModuleName(filename);
|
||||
std::string module_alias = ModuleAlias(filename);
|
||||
std::string module_name = ImportModuleName(file_->dependency(i));
|
||||
std::string module_alias = ModuleAlias(file_->dependency(i));
|
||||
if (ContainsPythonKeyword(module_name)) {
|
||||
// If the module path contains a Python keyword, we have to quote the
|
||||
// module name and import it using importlib. Otherwise the usual kind of
|
||||
|
|
@ -446,8 +432,7 @@ void Generator::PrintImports() const {
|
|||
|
||||
// Print public imports.
|
||||
for (int i = 0; i < file_->public_dependency_count(); ++i) {
|
||||
std::string module_name =
|
||||
ImportModuleName(file_->public_dependency(i)->name());
|
||||
std::string module_name = ImportModuleName(file_->public_dependency(i));
|
||||
printer_->Print("from $module$ import *\n", "module", module_name);
|
||||
}
|
||||
printer_->Print("\n");
|
||||
|
|
@ -601,7 +586,7 @@ void Generator::PrintFileDescriptor() const {
|
|||
if (file_->dependency_count() != 0) {
|
||||
printer_->Print(",\ndependencies=[");
|
||||
for (int i = 0; i < file_->dependency_count(); ++i) {
|
||||
std::string module_alias = ModuleAlias(file_->dependency(i)->name());
|
||||
std::string module_alias = ModuleAlias(file_->dependency(i));
|
||||
printer_->Print("$module_alias$.DESCRIPTOR,", "module_alias",
|
||||
module_alias);
|
||||
}
|
||||
|
|
@ -610,8 +595,7 @@ void Generator::PrintFileDescriptor() const {
|
|||
if (file_->public_dependency_count() > 0) {
|
||||
printer_->Print(",\npublic_dependencies=[");
|
||||
for (int i = 0; i < file_->public_dependency_count(); ++i) {
|
||||
std::string module_alias =
|
||||
ModuleAlias(file_->public_dependency(i)->name());
|
||||
std::string module_alias = ModuleAlias(file_->public_dependency(i));
|
||||
printer_->Print("$module_alias$.DESCRIPTOR,", "module_alias",
|
||||
module_alias);
|
||||
}
|
||||
|
|
@ -741,7 +725,7 @@ void Generator::PrintDescriptorKeyAndModuleName(
|
|||
std::string name = ModuleLevelServiceDescriptorName(descriptor);
|
||||
printer_->Print("$descriptor_key$ = $descriptor_name$,\n", "descriptor_key",
|
||||
kDescriptorKey, "descriptor_name", name);
|
||||
std::string module_name = ModuleName(file_->name());
|
||||
std::string module_name = ModuleName(file_);
|
||||
if (!opensource_runtime_) {
|
||||
module_name =
|
||||
std::string(absl::StripPrefix(module_name, kThirdPartyPrefix));
|
||||
|
|
@ -937,7 +921,7 @@ void Generator::PrintMessage(const Descriptor& message_descriptor,
|
|||
m["descriptor_key"] = kDescriptorKey;
|
||||
m["descriptor_name"] = ModuleLevelDescriptorName(message_descriptor);
|
||||
printer_->Print(m, "'$descriptor_key$' : $descriptor_name$,\n");
|
||||
std::string module_name = ModuleName(file_->name());
|
||||
std::string module_name = ModuleName(file_);
|
||||
if (!opensource_runtime_) {
|
||||
module_name =
|
||||
std::string(absl::StripPrefix(module_name, kThirdPartyPrefix));
|
||||
|
|
@ -1275,7 +1259,7 @@ std::string Generator::ModuleLevelDescriptorName(
|
|||
// We now have the name relative to its own module. Also qualify with
|
||||
// the module name iff this descriptor is from a different .proto file.
|
||||
if (descriptor.file() != file_) {
|
||||
name = absl::StrCat(ModuleAlias(descriptor.file()->name()), ".", name);
|
||||
name = absl::StrCat(ModuleAlias(descriptor.file()), ".", name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
|
@ -1288,7 +1272,7 @@ std::string Generator::ModuleLevelMessageName(
|
|||
const Descriptor& descriptor) const {
|
||||
std::string name = NamePrefixedWithNestedTypes(descriptor, ".");
|
||||
if (descriptor.file() != file_) {
|
||||
name = absl::StrCat(ModuleAlias(descriptor.file()->name()), ".", name);
|
||||
name = absl::StrCat(ModuleAlias(descriptor.file()), ".", name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
|
@ -1300,7 +1284,7 @@ std::string Generator::ModuleLevelServiceDescriptorName(
|
|||
std::string name = absl::StrCat("_", descriptor.name());
|
||||
absl::AsciiStrToUpper(&name);
|
||||
if (descriptor.file() != file_) {
|
||||
name = absl::StrCat(ModuleAlias(descriptor.file()->name()), ".", name);
|
||||
name = absl::StrCat(ModuleAlias(descriptor.file()), ".", name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
|
@ -1521,8 +1505,8 @@ void Generator::FixOptionsForMessage(const Descriptor& descriptor,
|
|||
void Generator::CopyPublicDependenciesAliases(
|
||||
absl::string_view copy_from, const FileDescriptor* file) const {
|
||||
for (int i = 0; i < file->public_dependency_count(); ++i) {
|
||||
std::string module_name = ModuleName(file->public_dependency(i)->name());
|
||||
std::string module_alias = ModuleAlias(file->public_dependency(i)->name());
|
||||
std::string module_name = ModuleName(file->public_dependency(i));
|
||||
std::string module_alias = ModuleAlias(file->public_dependency(i));
|
||||
// There's no module alias in the dependent file if it was generated by
|
||||
// an old protoc (less than 3.0.0-alpha-1). Use module name in this
|
||||
// situation.
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ class PROTOC_EXPORT Generator : public CodeGenerator {
|
|||
private:
|
||||
GeneratorOptions ParseParameter(absl::string_view parameter,
|
||||
std::string* error) const;
|
||||
std::string ImportModuleName(absl::string_view filename) const;
|
||||
std::string ImportModuleName(const FileDescriptor* file) const;
|
||||
void PrintImports() const;
|
||||
template <typename DescriptorT>
|
||||
std::string GetResolvedFeatures(const DescriptorT& descriptor) const;
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@
|
|||
#include "absl/log/absl_check.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/strings/match.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_replace.h"
|
||||
#include "absl/strings/str_split.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/strings/strip.h"
|
||||
#include "google/protobuf/compiler/code_generator.h"
|
||||
#include "google/protobuf/compiler/python/names.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
|
||||
|
|
@ -27,18 +28,6 @@ namespace protobuf {
|
|||
namespace compiler {
|
||||
namespace python {
|
||||
|
||||
// Returns the Python module name expected for a given .proto filename.
|
||||
std::string ModuleName(absl::string_view filename) {
|
||||
std::string basename = StripProto(filename);
|
||||
absl::StrReplaceAll({{"-", "_"}, {"/", "."}}, &basename);
|
||||
return absl::StrCat(basename, "_pb2");
|
||||
}
|
||||
|
||||
std::string StrippedModuleName(absl::string_view filename) {
|
||||
std::string module_name = ModuleName(filename);
|
||||
return module_name;
|
||||
}
|
||||
|
||||
// Keywords reserved by the Python language.
|
||||
const char* const kKeywords[] = {
|
||||
"False", "None", "True", "and", "as", "assert",
|
||||
|
|
@ -74,7 +63,7 @@ std::string ResolveKeyword(absl::string_view name) {
|
|||
|
||||
std::string GetFileName(const FileDescriptor* file_des,
|
||||
absl::string_view suffix) {
|
||||
std::string module_name = ModuleName(file_des->name());
|
||||
std::string module_name = ModuleName(file_des);
|
||||
std::string filename = module_name;
|
||||
absl::StrReplaceAll({{".", "/"}}, &filename);
|
||||
absl::StrAppend(&filename, suffix);
|
||||
|
|
|
|||
|
|
@ -10,18 +10,18 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/str_replace.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace python {
|
||||
|
||||
std::string ModuleName(absl::string_view filename);
|
||||
std::string StrippedModuleName(absl::string_view filename);
|
||||
bool ContainsPythonKeyword(absl::string_view module_name);
|
||||
bool IsPythonKeyword(absl::string_view name);
|
||||
std::string ResolveKeyword(absl::string_view name);
|
||||
|
|
@ -40,4 +40,6 @@ std::string NamePrefixedWithNestedTypes(const DescriptorT& descriptor,
|
|||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_PYTHON_HELPERS_H__
|
||||
|
|
|
|||
45
src/google/protobuf/compiler/python/names.cc
Normal file
45
src/google/protobuf/compiler/python/names.cc
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include "google/protobuf/compiler/python/names.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_replace.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/strings/strip.h"
|
||||
#include "google/protobuf/compiler/code_generator.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace python {
|
||||
|
||||
// Returns the Python module name expected for a given .proto filename.
|
||||
std::string ModuleName(const FileDescriptor* file) {
|
||||
std::string basename = StripProto(file->name());
|
||||
absl::StrReplaceAll({{"-", "_"}, {"/", "."}}, &basename);
|
||||
return absl::StrCat(basename, "_pb2");
|
||||
}
|
||||
|
||||
std::string StrippedModuleName(const FileDescriptor* file) {
|
||||
std::string module_name = ModuleName(file);
|
||||
return module_name;
|
||||
}
|
||||
|
||||
// Returns the alias we assign to the module of the given .proto filename
|
||||
// when importing. See testPackageInitializationImport in
|
||||
// third_party/py/google/protobuf/internal/reflection_test.py
|
||||
// to see why we need the alias.
|
||||
std::string ModuleAlias(const FileDescriptor* file) {
|
||||
std::string module_name = ModuleName(file);
|
||||
// We can't have dots in the module name, so we replace each with _dot_.
|
||||
// But that could lead to a collision between a.b and a_dot_b, so we also
|
||||
// duplicate each underscore.
|
||||
absl::StrReplaceAll({{"_", "__"}}, &module_name);
|
||||
absl::StrReplaceAll({{".", "_dot_"}}, &module_name);
|
||||
return module_name;
|
||||
}
|
||||
|
||||
} // namespace python
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
36
src/google/protobuf/compiler/python/names.h
Normal file
36
src/google/protobuf/compiler/python/names.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef GOOGLE_PROTOBUF_COMPILER_PYTHON_NAMES_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_PYTHON_NAMES_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
class FileDescriptor;
|
||||
|
||||
namespace compiler {
|
||||
namespace python {
|
||||
|
||||
// Returns the Python module name expected for a given .proto filename.
|
||||
PROTOC_EXPORT std::string ModuleName(const FileDescriptor* file);
|
||||
|
||||
// Returns the stripped Python module name expected for a given .proto filename.
|
||||
PROTOC_EXPORT std::string StrippedModuleName(const FileDescriptor* file);
|
||||
|
||||
// Returns the alias we assign to the module of the given .proto filename
|
||||
// when importing. See testPackageInitializationImport in
|
||||
// third_party/py/google/protobuf/internal/reflection_test.py
|
||||
// to see why we need the alias.
|
||||
PROTOC_EXPORT std::string ModuleAlias(const FileDescriptor* file);
|
||||
|
||||
} // namespace python
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_PYTHON_NAMES_H__
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
#include "absl/synchronization/mutex.h"
|
||||
#include "google/protobuf/compiler/code_generator.h"
|
||||
#include "google/protobuf/compiler/python/helpers.h"
|
||||
#include "google/protobuf/compiler/python/names.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
|
|
@ -45,7 +46,7 @@ std::string PyiGenerator::ModuleLevelName(const DescriptorT& descriptor) const {
|
|||
std::string module_alias;
|
||||
const absl::string_view filename = descriptor.file()->name();
|
||||
if (import_map_.find(filename) == import_map_.end()) {
|
||||
std::string module_name = ModuleName(descriptor.file()->name());
|
||||
std::string module_name = ModuleName(descriptor.file());
|
||||
std::vector<absl::string_view> tokens = absl::StrSplit(module_name, '.');
|
||||
module_alias = absl::StrCat("_", tokens.back());
|
||||
} else {
|
||||
|
|
@ -151,7 +152,7 @@ void PyiGenerator::PrintImportForDescriptor(
|
|||
const FileDescriptor& desc, absl::flat_hash_set<std::string>* seen_aliases,
|
||||
bool* has_importlib) const {
|
||||
const absl::string_view filename = desc.name();
|
||||
std::string module_name_owned = StrippedModuleName(filename);
|
||||
std::string module_name_owned = StrippedModuleName(&desc);
|
||||
absl::string_view module_name(module_name_owned);
|
||||
size_t last_dot_pos = module_name.rfind('.');
|
||||
std::string alias = absl::StrCat("_", module_name.substr(last_dot_pos + 1));
|
||||
|
|
@ -296,7 +297,7 @@ void PyiGenerator::PrintImports() const {
|
|||
// Public imports
|
||||
for (int i = 0; i < file_->public_dependency_count(); ++i) {
|
||||
const FileDescriptor* public_dep = file_->public_dependency(i);
|
||||
std::string module_name = StrippedModuleName(public_dep->name());
|
||||
std::string module_name = StrippedModuleName(public_dep);
|
||||
// Top level messages in public imports
|
||||
for (int i = 0; i < public_dep->message_type_count(); ++i) {
|
||||
printer_->Print(
|
||||
|
|
@ -404,7 +405,7 @@ std::string PyiGenerator::GetFieldType(
|
|||
std::string name = ModuleLevelName(*field_des.message_type());
|
||||
if ((containing_des.containing_type() != nullptr &&
|
||||
name == containing_des.name())) {
|
||||
std::string module = ModuleName(field_des.file()->name());
|
||||
std::string module = ModuleName(field_des.file());
|
||||
name = absl::StrCat(module, ".", name);
|
||||
}
|
||||
return name;
|
||||
|
|
|
|||
|
|
@ -114,8 +114,7 @@ void GenerateRs(Context& ctx, const FieldDescriptor& extension,
|
|||
}
|
||||
} else {
|
||||
std::string mini_descriptor =
|
||||
pool.FindExtensionByName(std::string(extension.full_name()).c_str())
|
||||
.MiniDescriptorEncode();
|
||||
pool.FindExtensionByName(extension.full_name()).MiniDescriptorEncode();
|
||||
|
||||
std::string extendee = RsTypePath(ctx, *extension.containing_type());
|
||||
std::string number = absl::StrCat(extension.number());
|
||||
|
|
|
|||
|
|
@ -323,8 +323,7 @@ bool RustGenerator::Generate(const FileDescriptor* file,
|
|||
|
||||
for (int i = 0; i < file->enum_type_count(); ++i) {
|
||||
auto& enum_ = *file->enum_type(i);
|
||||
GenerateEnumDefinition(ctx, enum_,
|
||||
pool.FindEnumByName(enum_.full_name().data()));
|
||||
GenerateEnumDefinition(ctx, enum_, pool.FindEnumByName(enum_.full_name()));
|
||||
ctx.printer().PrintRaw("\n");
|
||||
|
||||
if (ctx.is_cpp()) {
|
||||
|
|
|
|||
|
|
@ -224,8 +224,7 @@ void UpbGeneratedMessageTraitImpls(Context& ctx, const Descriptor& msg,
|
|||
if (scc.GetRepresentative() == &msg) {
|
||||
for (const Descriptor* d : scc.descriptors) {
|
||||
std::string mini_descriptor =
|
||||
pool.FindMessageByName(d->full_name().data())
|
||||
.MiniDescriptorEncode();
|
||||
pool.FindMessageByName(d->full_name()).MiniDescriptorEncode();
|
||||
ctx.Emit({{"name", RsTypePath(ctx, *d)},
|
||||
{"minitable_symbol_name",
|
||||
QualifiedUpbMiniTableName(ctx, *d)},
|
||||
|
|
@ -237,8 +236,8 @@ void UpbGeneratedMessageTraitImpls(Context& ctx, const Descriptor& msg,
|
|||
)rs");
|
||||
}
|
||||
for (const Descriptor* d : scc.descriptors) {
|
||||
UpbMiniTableLinking(
|
||||
ctx, *d, pool.FindMessageByName(d->full_name().data()), scc);
|
||||
UpbMiniTableLinking(ctx, *d,
|
||||
pool.FindMessageByName(d->full_name()), scc);
|
||||
}
|
||||
} else {
|
||||
ctx.Emit(
|
||||
|
|
@ -406,7 +405,7 @@ void GenerateRs(Context& ctx, const Descriptor& msg, const upb::DefPool& pool) {
|
|||
return;
|
||||
}
|
||||
|
||||
upb::MessageDefPtr upb_msg = pool.FindMessageByName(msg.full_name().data());
|
||||
upb::MessageDefPtr upb_msg = pool.FindMessageByName(msg.full_name());
|
||||
ctx.Emit(
|
||||
{
|
||||
// There's also ${$/$}$-style begin and end tokens, but those might
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@
|
|||
#include "google/protobuf/message.h"
|
||||
#include "google/protobuf/message_lite.h"
|
||||
#include "google/protobuf/naming_style.h"
|
||||
#include "google/protobuf/offset_ptr.h"
|
||||
#include "google/protobuf/option_interpreter.h"
|
||||
#include "google/protobuf/parse_context.h"
|
||||
#include "google/protobuf/port.h"
|
||||
|
|
@ -421,7 +422,7 @@ class FlatAllocatorImpl {
|
|||
|
||||
// TODO: Remove the NULL terminators to save memory and simplify
|
||||
// the code.
|
||||
absl::optional<internal::DescriptorNames> CreateDescriptorNames(
|
||||
absl::optional<internal::DescriptorNames::Input> CreateDescriptorNames(
|
||||
std::initializer_list<absl::string_view> bytes,
|
||||
std::initializer_list<size_t> sizes) {
|
||||
for (size_t size : sizes) {
|
||||
|
|
@ -439,7 +440,7 @@ class FlatAllocatorImpl {
|
|||
memcpy(out, b.data(), b.size());
|
||||
out += b.size();
|
||||
}
|
||||
auto res = internal::DescriptorNames(out);
|
||||
auto res = internal::DescriptorNames::Input{out};
|
||||
for (size_t size : sizes) {
|
||||
uint16_t size16 = static_cast<uint16_t>(size);
|
||||
memcpy(out, &size16, sizeof(size16));
|
||||
|
|
@ -452,7 +453,7 @@ class FlatAllocatorImpl {
|
|||
PlanArray<char>(internal::DescriptorNames::AllocationSizeForSimpleNames(
|
||||
full_name_size));
|
||||
}
|
||||
absl::optional<internal::DescriptorNames> AllocateEntityNames(
|
||||
absl::optional<internal::DescriptorNames::Input> AllocateEntityNames(
|
||||
absl::string_view scope, absl::string_view name) {
|
||||
static constexpr absl::string_view kNullChar("\0", 1);
|
||||
if (scope.empty()) {
|
||||
|
|
@ -465,7 +466,7 @@ class FlatAllocatorImpl {
|
|||
}
|
||||
}
|
||||
|
||||
internal::DescriptorNames AllocatePlaceholderNames(
|
||||
internal::DescriptorNames::Input AllocatePlaceholderNames(
|
||||
absl::string_view full_name, size_t name_size) {
|
||||
static constexpr absl::string_view kNullChar("\0", 1);
|
||||
auto out = CreateDescriptorNames({full_name, kNullChar},
|
||||
|
|
@ -533,7 +534,7 @@ class FlatAllocatorImpl {
|
|||
PlanArray<char>(total_bytes);
|
||||
}
|
||||
|
||||
absl::optional<internal::DescriptorNames> AllocateFieldNames(
|
||||
absl::optional<internal::DescriptorNames::Input> AllocateFieldNames(
|
||||
const absl::string_view name, const absl::string_view scope,
|
||||
const std::string* opt_json_name) {
|
||||
ABSL_CHECK(has_allocated());
|
||||
|
|
@ -856,38 +857,11 @@ struct ParentNameQueryBase {
|
|||
}
|
||||
};
|
||||
|
||||
// A 32-bit "offset" based pointer used for hash tables below.
|
||||
// The base pointer is the base of the FlatAllocation, which is the same for
|
||||
// the objects in a single FileDescriptorTables (except the ones allocated later
|
||||
// on demand, like unknown_enum_values_by_number_).
|
||||
// This halves the size of the tables in 64-bit builds.
|
||||
template <typename T>
|
||||
struct OffsetT {
|
||||
OffsetT(T* ptr, absl::string_view flat_buffer) {
|
||||
ptrdiff_t diff = reinterpret_cast<const char*>(ptr) -
|
||||
reinterpret_cast<const char*>(flat_buffer.data());
|
||||
// Verify the pointer is actually in bounds of the buffer.
|
||||
ABSL_DCHECK(static_cast<const void*>(ptr) >= flat_buffer.data() &&
|
||||
static_cast<const void*>(ptr) <
|
||||
flat_buffer.data() + flat_buffer.size());
|
||||
ABSL_DCHECK_GE(diff, 0);
|
||||
ABSL_DCHECK_LE(diff, std::numeric_limits<uint32_t>::max());
|
||||
value = static_cast<uint32_t>(diff);
|
||||
}
|
||||
|
||||
T* Resolve(const void* base_ptr) const {
|
||||
return const_cast<T*>(reinterpret_cast<const T*>(
|
||||
reinterpret_cast<const char*>(base_ptr) + value));
|
||||
}
|
||||
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
const T& ResolveSymbol(const T& v, const void*) {
|
||||
return v;
|
||||
}
|
||||
Symbol ResolveSymbol(OffsetT<const internal::SymbolBase> v,
|
||||
Symbol ResolveSymbol(internal::BasePointer<const internal::SymbolBase, false> v,
|
||||
const void* base_ptr) {
|
||||
return Symbol(v.Resolve(base_ptr));
|
||||
}
|
||||
|
|
@ -916,7 +890,8 @@ struct SymbolByParentHash {
|
|||
|
||||
const void* base_ptr;
|
||||
|
||||
size_t operator()(OffsetT<const internal::SymbolBase> v) const {
|
||||
size_t operator()(
|
||||
internal::BasePointer<const internal::SymbolBase, false> v) const {
|
||||
return (*this)(Symbol(v.Resolve(base_ptr)));
|
||||
}
|
||||
|
||||
|
|
@ -930,8 +905,9 @@ struct SymbolByParentEq {
|
|||
|
||||
const void* base_ptr;
|
||||
|
||||
bool operator()(OffsetT<const internal::SymbolBase> offset,
|
||||
const ParentNameFieldQuery& query) const {
|
||||
bool operator()(
|
||||
internal::BasePointer<const internal::SymbolBase, false> offset,
|
||||
const ParentNameFieldQuery& query) const {
|
||||
Symbol symbol = ResolveSymbol(offset, base_ptr);
|
||||
const FieldDescriptor* field = symbol.field_descriptor();
|
||||
return field != nullptr && !field->is_extension() &&
|
||||
|
|
@ -945,9 +921,9 @@ struct SymbolByParentEq {
|
|||
ResolveSymbol(b, base_ptr).parent_name_key();
|
||||
}
|
||||
};
|
||||
using SymbolsByParentSet =
|
||||
absl::flat_hash_set<OffsetT<const internal::SymbolBase>, SymbolByParentHash,
|
||||
SymbolByParentEq>;
|
||||
using SymbolsByParentSet = absl::flat_hash_set<
|
||||
internal::BasePointer<const internal::SymbolBase, false>,
|
||||
SymbolByParentHash, SymbolByParentEq>;
|
||||
|
||||
template <typename Projection>
|
||||
struct ProjectedHash {
|
||||
|
|
@ -1059,8 +1035,8 @@ using EnumValuesByNumberSet =
|
|||
ParentNumberEq>;
|
||||
|
||||
template <typename T>
|
||||
std::pair<const void*, int> ObjectToParentNumber(OffsetT<T> offset,
|
||||
const void* base_ptr) {
|
||||
std::pair<const void*, int> ObjectToParentNumber(
|
||||
internal::BasePointer<T, false> offset, const void* base_ptr) {
|
||||
return ObjectToParentNumber(offset.Resolve(base_ptr));
|
||||
}
|
||||
|
||||
|
|
@ -1088,11 +1064,11 @@ struct ParentNumberEqOffsetPtr {
|
|||
};
|
||||
|
||||
using EnumValuesByNumberSetOffsetPtr =
|
||||
absl::flat_hash_set<OffsetT<const EnumValueDescriptor>,
|
||||
absl::flat_hash_set<internal::BasePointer<const EnumValueDescriptor, false>,
|
||||
ParentNumberHashOffsetPtr, ParentNumberEqOffsetPtr>;
|
||||
|
||||
using FieldsByNumberSet =
|
||||
absl::flat_hash_set<OffsetT<const FieldDescriptor>,
|
||||
absl::flat_hash_set<internal::BasePointer<const FieldDescriptor, false>,
|
||||
ParentNumberHashOffsetPtr, ParentNumberEqOffsetPtr>;
|
||||
|
||||
// This is a map rather than a hash-map, since we use it to iterate
|
||||
|
|
@ -1313,7 +1289,8 @@ class FileDescriptorTables {
|
|||
const FileDescriptorTables* tables);
|
||||
void FieldsByCamelcaseNamesLazyInitInternal() const;
|
||||
|
||||
Symbol Resolve(OffsetT<const internal::SymbolBase> v) const {
|
||||
Symbol Resolve(
|
||||
internal::BasePointer<const internal::SymbolBase, false> v) const {
|
||||
return Symbol(v.Resolve(flat_buffer_.data()));
|
||||
}
|
||||
|
||||
|
|
@ -1931,7 +1908,7 @@ FileDescriptorTables::FindEnumValueByNumberCreatingIfUnknown(
|
|||
absl::StrCat(parent->full_name(), ".", enum_value_name));
|
||||
result->number_ = number;
|
||||
result->type_ = parent;
|
||||
result->options_ = &EnumValueOptions::default_instance();
|
||||
result->options_ = nullptr;
|
||||
unknown_enum_values_by_number_.insert(result);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1973,7 +1950,8 @@ bool FileDescriptorTables::AddAliasUnderParent(const void* parent,
|
|||
ABSL_DCHECK_EQ(name, symbol.parent_name_key().second);
|
||||
ABSL_DCHECK_EQ(parent, symbol.parent_name_key().first);
|
||||
return symbols_by_parent_
|
||||
.insert(OffsetT<const internal::SymbolBase>(symbol.ptr(), flat_buffer_))
|
||||
.insert(internal::BasePointer<const internal::SymbolBase, false>(
|
||||
symbol.ptr(), flat_buffer_.data()))
|
||||
.second;
|
||||
}
|
||||
|
||||
|
|
@ -2002,7 +1980,8 @@ bool FileDescriptorTables::AddFieldByNumber(FieldDescriptor* field) {
|
|||
}
|
||||
|
||||
return fields_by_number_
|
||||
.insert(OffsetT<const FieldDescriptor>(field, flat_buffer_))
|
||||
.insert(internal::BasePointer<const FieldDescriptor, false>(
|
||||
field, flat_buffer_.data()))
|
||||
.second;
|
||||
}
|
||||
|
||||
|
|
@ -2014,7 +1993,8 @@ bool FileDescriptorTables::AddEnumValueByNumber(EnumValueDescriptor* value) {
|
|||
static_cast<int64_t>(base) + value->type()->sequential_value_limit_)
|
||||
return true;
|
||||
return enum_values_by_number_
|
||||
.insert(OffsetT<const EnumValueDescriptor>(value, flat_buffer_))
|
||||
.insert(internal::BasePointer<const EnumValueDescriptor, false>(
|
||||
value, flat_buffer_.data()))
|
||||
.second;
|
||||
}
|
||||
|
||||
|
|
@ -2864,6 +2844,18 @@ bool DescriptorPool::TryFindExtensionInFallbackDatabase(
|
|||
|
||||
// ===================================================================
|
||||
|
||||
#define PROTOBUF_DEFINE_OPTIONS_ACCESSOR(CLASS, TYPE) \
|
||||
const TYPE& CLASS::options() const { return *options_; }
|
||||
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FieldDescriptor, FieldOptions)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(OneofDescriptor, OneofOptions)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumValueDescriptor, EnumValueOptions)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions)
|
||||
|
||||
bool FieldDescriptor::is_map_message_type() const {
|
||||
return message_type()->options().map_entry();
|
||||
}
|
||||
|
|
@ -3436,9 +3428,10 @@ std::string FileDescriptor::DebugStringWithOptions(
|
|||
comment_printer.AddPreComment(&contents);
|
||||
|
||||
absl::flat_hash_set<int> public_dependencies(
|
||||
public_dependencies_, public_dependencies_ + public_dependency_count_);
|
||||
public_dependencies_.get(),
|
||||
public_dependencies_ + public_dependency_count_);
|
||||
absl::flat_hash_set<int> weak_dependencies(
|
||||
weak_dependencies_, weak_dependencies_ + weak_dependency_count_);
|
||||
weak_dependencies_.get(), weak_dependencies_ + weak_dependency_count_);
|
||||
|
||||
for (int i = 0; i < dependency_count(); i++) {
|
||||
if (public_dependencies.contains(i)) {
|
||||
|
|
@ -4755,10 +4748,10 @@ Symbol DescriptorPool::NewPlaceholderWithMutexHeld(
|
|||
EnumDescriptor* placeholder_enum = &placeholder_file->enum_types_[0];
|
||||
memset(static_cast<void*>(placeholder_enum), 0, sizeof(*placeholder_enum));
|
||||
|
||||
placeholder_enum->all_names_ = alloc.AllocatePlaceholderNames(
|
||||
placeholder_full_name, placeholder_name.size());
|
||||
placeholder_enum->all_names_.SetPayload(alloc.AllocatePlaceholderNames(
|
||||
placeholder_full_name, placeholder_name.size()));
|
||||
placeholder_enum->file_ = placeholder_file;
|
||||
placeholder_enum->options_ = &EnumOptions::default_instance();
|
||||
placeholder_enum->options_ = nullptr;
|
||||
placeholder_enum->proto_features_ = &FeatureSet::default_instance();
|
||||
placeholder_enum->merged_features_ = &FeatureSet::default_instance();
|
||||
placeholder_enum->is_placeholder_ = true;
|
||||
|
|
@ -4783,7 +4776,7 @@ Symbol DescriptorPool::NewPlaceholderWithMutexHeld(
|
|||
|
||||
placeholder_value->number_ = 0;
|
||||
placeholder_value->type_ = placeholder_enum;
|
||||
placeholder_value->options_ = &EnumValueOptions::default_instance();
|
||||
placeholder_value->options_ = nullptr;
|
||||
|
||||
return Symbol(placeholder_enum);
|
||||
} else {
|
||||
|
|
@ -4794,10 +4787,10 @@ Symbol DescriptorPool::NewPlaceholderWithMutexHeld(
|
|||
memset(static_cast<void*>(placeholder_message), 0,
|
||||
sizeof(*placeholder_message));
|
||||
|
||||
placeholder_message->all_names_ = alloc.AllocatePlaceholderNames(
|
||||
placeholder_full_name, placeholder_name.size());
|
||||
placeholder_message->all_names_.SetPayload(alloc.AllocatePlaceholderNames(
|
||||
placeholder_full_name, placeholder_name.size()));
|
||||
placeholder_message->file_ = placeholder_file;
|
||||
placeholder_message->options_ = &MessageOptions::default_instance();
|
||||
placeholder_message->options_ = nullptr;
|
||||
placeholder_message->proto_features_ = &FeatureSet::default_instance();
|
||||
placeholder_message->merged_features_ = &FeatureSet::default_instance();
|
||||
placeholder_message->is_placeholder_ = true;
|
||||
|
|
@ -4844,7 +4837,7 @@ FileDescriptor* DescriptorPool::NewPlaceholderFileWithMutexHeld(
|
|||
placeholder->name_ = alloc.AllocateStrings(name);
|
||||
placeholder->package_ = &internal::GetEmptyString();
|
||||
placeholder->pool_ = this;
|
||||
placeholder->options_ = &FileOptions::default_instance();
|
||||
placeholder->options_ = nullptr;
|
||||
placeholder->proto_features_ = &FeatureSet::default_instance();
|
||||
placeholder->merged_features_ = &FeatureSet::default_instance();
|
||||
placeholder->tables_ = &FileDescriptorTables::GetEmptyInstance();
|
||||
|
|
@ -5207,20 +5200,20 @@ void internal::DescriptorBuilder::PostProcessFieldFeatures(
|
|||
if (field.options_->has_ctype()) {
|
||||
field.legacy_proto_ctype_ = field.options_->ctype();
|
||||
const_cast<FieldOptions*>( // NOLINT(google3-runtime-proto-const-cast)
|
||||
field.options_)
|
||||
field.options_.get())
|
||||
->clear_ctype();
|
||||
}
|
||||
}
|
||||
|
||||
// A common pattern: We want to convert a repeated field in the descriptor
|
||||
// to an array of values, calling some method to build each value.
|
||||
#define BUILD_ARRAY(INPUT, OUTPUT, NAME, METHOD, PARENT) \
|
||||
OUTPUT->NAME##_count_ = INPUT.NAME##_size(); \
|
||||
OUTPUT->NAME##s_ = alloc.AllocateArray< \
|
||||
typename std::remove_pointer<decltype(OUTPUT->NAME##s_)>::type>( \
|
||||
INPUT.NAME##_size()); \
|
||||
for (int i = 0; i < INPUT.NAME##_size(); i++) { \
|
||||
METHOD(INPUT.NAME(i), PARENT, OUTPUT->NAME##s_ + i, alloc); \
|
||||
#define BUILD_ARRAY(INPUT, OUTPUT, NAME, METHOD, PARENT) \
|
||||
OUTPUT->NAME##_count_ = INPUT.NAME##_size(); \
|
||||
OUTPUT->NAME##s_ = \
|
||||
alloc.AllocateArray<decltype(OUTPUT->NAME##s_)::value_type>( \
|
||||
INPUT.NAME##_size()); \
|
||||
for (int i = 0; i < INPUT.NAME##_size(); i++) { \
|
||||
METHOD(INPUT.NAME(i), PARENT, OUTPUT->NAME##s_ + i, alloc); \
|
||||
}
|
||||
|
||||
PROTOBUF_NOINLINE void internal::DescriptorBuilder::AddRecursiveImportError(
|
||||
|
|
@ -5840,9 +5833,8 @@ FileDescriptor* internal::DescriptorBuilder::BuildFileImpl(
|
|||
auto cleanup = DisableTracking();
|
||||
internal::VisitDescriptors(
|
||||
*result, proto, [&](const auto& descriptor, const auto& proto) {
|
||||
using OptionsT =
|
||||
typename std::remove_const<typename std::remove_pointer<
|
||||
decltype(descriptor.options_)>::type>::type;
|
||||
using OptionsT = std::remove_const_t<
|
||||
std::decay_t<decltype(*descriptor.options_)>>;
|
||||
using DescriptorT =
|
||||
typename std::remove_const<typename std::remove_reference<
|
||||
decltype(descriptor)>::type>::type;
|
||||
|
|
@ -5850,7 +5842,7 @@ FileDescriptor* internal::DescriptorBuilder::BuildFileImpl(
|
|||
ResolveFeatures(
|
||||
proto, const_cast<DescriptorT*>(&descriptor),
|
||||
const_cast< // NOLINT(google3-runtime-proto-const-cast)
|
||||
OptionsT*>(descriptor.options_),
|
||||
OptionsT*>(+descriptor.options_),
|
||||
alloc);
|
||||
});
|
||||
}
|
||||
|
|
@ -6002,7 +5994,8 @@ void internal::DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
|
|||
internal::FlatAllocator& alloc) {
|
||||
const absl::string_view scope =
|
||||
(parent == nullptr) ? file_->package() : parent->full_name();
|
||||
result->all_names_ = AllocateNameStrings(scope, proto.name(), proto, alloc);
|
||||
result->all_names_.SetPayload(
|
||||
AllocateNameStrings(scope, proto.name(), proto, alloc));
|
||||
ValidateSymbolName(proto.name(), result->full_name(), proto);
|
||||
|
||||
result->file_ = file_;
|
||||
|
|
@ -6046,7 +6039,6 @@ void internal::DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
|
|||
if (recursion_depth_ <= 0) {
|
||||
AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::OTHER,
|
||||
"Reached maximum recursion limit for nested messages.");
|
||||
result->nested_types_ = nullptr;
|
||||
result->nested_type_count_ = 0;
|
||||
return;
|
||||
}
|
||||
|
|
@ -6287,12 +6279,13 @@ void internal::DescriptorBuilder::BuildFieldOrExtension(
|
|||
if (auto names = alloc.AllocateFieldNames(
|
||||
proto.name(), scope,
|
||||
proto.has_json_name() ? &proto.json_name() : nullptr)) {
|
||||
result->all_names_ = *names;
|
||||
result->all_names_.SetPayload(*names);
|
||||
} else {
|
||||
AddError(
|
||||
scope.empty() ? proto.name() : absl::StrCat(scope, ".", proto.name()),
|
||||
proto, DescriptorPool::ErrorCollector::NAME, "Name too long.");
|
||||
result->all_names_ = alloc.AllocateEntityNames("", "unknown").value();
|
||||
result->all_names_.SetPayload(
|
||||
alloc.AllocateEntityNames("", "unknown").value());
|
||||
}
|
||||
|
||||
ValidateSymbolName(proto.name(), result->full_name(), proto);
|
||||
|
|
@ -6637,15 +6630,14 @@ void internal::DescriptorBuilder::BuildOneof(const OneofDescriptorProto& proto,
|
|||
Descriptor* parent,
|
||||
OneofDescriptor* result,
|
||||
internal::FlatAllocator& alloc) {
|
||||
result->all_names_ =
|
||||
AllocateNameStrings(parent->full_name(), proto.name(), proto, alloc);
|
||||
result->all_names_.SetPayload(
|
||||
AllocateNameStrings(parent->full_name(), proto.name(), proto, alloc));
|
||||
ValidateSymbolName(proto.name(), result->full_name(), proto);
|
||||
|
||||
result->containing_type_ = parent;
|
||||
|
||||
// We need to fill these in later.
|
||||
result->field_count_ = 0;
|
||||
result->fields_ = nullptr;
|
||||
|
||||
// Copy options.
|
||||
AllocateOptions(proto, result, OneofDescriptorProto::kOptionsFieldNumber,
|
||||
|
|
@ -6813,7 +6805,8 @@ void internal::DescriptorBuilder::BuildEnum(const EnumDescriptorProto& proto,
|
|||
const absl::string_view scope =
|
||||
(parent == nullptr) ? file_->package() : parent->full_name();
|
||||
|
||||
result->all_names_ = AllocateNameStrings(scope, proto.name(), proto, alloc);
|
||||
result->all_names_.SetPayload(
|
||||
AllocateNameStrings(scope, proto.name(), proto, alloc));
|
||||
ValidateSymbolName(proto.name(), result->full_name(), proto);
|
||||
result->file_ = file_;
|
||||
result->containing_type_ = parent;
|
||||
|
|
@ -6995,8 +6988,8 @@ void internal::DescriptorBuilder::BuildEnumValue(
|
|||
void internal::DescriptorBuilder::BuildService(
|
||||
const ServiceDescriptorProto& proto, const void* /* dummy */,
|
||||
ServiceDescriptor* result, internal::FlatAllocator& alloc) {
|
||||
result->all_names_ =
|
||||
AllocateNameStrings(file_->package(), proto.name(), proto, alloc);
|
||||
result->all_names_.SetPayload(
|
||||
AllocateNameStrings(file_->package(), proto.name(), proto, alloc));
|
||||
result->file_ = file_;
|
||||
ValidateSymbolName(proto.name(), result->full_name(), proto);
|
||||
|
||||
|
|
@ -7014,8 +7007,8 @@ void internal::DescriptorBuilder::BuildMethod(
|
|||
const MethodDescriptorProto& proto, const ServiceDescriptor* parent,
|
||||
MethodDescriptor* result, internal::FlatAllocator& alloc) {
|
||||
result->service_ = parent;
|
||||
result->all_names_ =
|
||||
AllocateNameStrings(parent->full_name(), proto.name(), proto, alloc);
|
||||
result->all_names_.SetPayload(
|
||||
AllocateNameStrings(parent->full_name(), proto.name(), proto, alloc));
|
||||
|
||||
ValidateSymbolName(proto.name(), result->full_name(), proto);
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@
|
|||
#include "absl/synchronization/mutex.h"
|
||||
#include "google/protobuf/descriptor_lite.h" // IWYU pragma: export
|
||||
#include "google/protobuf/extension_set.h"
|
||||
#include "google/protobuf/offset_ptr.h"
|
||||
#include "google/protobuf/port.h"
|
||||
|
||||
// Must be included last.
|
||||
|
|
@ -267,7 +268,18 @@ class PROTOBUF_FUTURE_ADD_EARLY_WARN_UNUSED DescriptorNames {
|
|||
public:
|
||||
// Uninitialized, to support `= default` of descriptor types.
|
||||
DescriptorNames() = default;
|
||||
explicit DescriptorNames(const char* payload) : payload_(payload) {}
|
||||
|
||||
// We can't construct temporaries because of the offset_ptr, so avoid this.
|
||||
#ifndef SWIG
|
||||
DescriptorNames(const DescriptorNames&) = delete;
|
||||
DescriptorNames& operator=(const DescriptorNames&) = delete;
|
||||
#endif
|
||||
|
||||
struct Input {
|
||||
const char* value;
|
||||
};
|
||||
|
||||
void SetPayload(Input value) { payload_ = value.value; }
|
||||
|
||||
// The full name is just before `payload_`, and the name is the suffix of it.
|
||||
// We don't need a special offset for them.
|
||||
|
|
@ -309,7 +321,7 @@ class PROTOBUF_FUTURE_ADD_EARLY_WARN_UNUSED DescriptorNames {
|
|||
return absl::string_view(payload_ - offset, size);
|
||||
}
|
||||
|
||||
const char* payload_;
|
||||
internal::NonnullOffsetPtr<const char> payload_;
|
||||
};
|
||||
|
||||
class FlatAllocator;
|
||||
|
|
@ -822,25 +834,20 @@ class PROTOBUF_EXPORT Descriptor : private internal::SymbolBase {
|
|||
// sequentially numbered fields in a message.
|
||||
uint16_t sequential_field_limit_;
|
||||
|
||||
int field_count_;
|
||||
|
||||
internal::DescriptorNames all_names_;
|
||||
const FileDescriptor* file_;
|
||||
const Descriptor* containing_type_;
|
||||
const MessageOptions* options_;
|
||||
const FeatureSet* proto_features_;
|
||||
const FeatureSet* merged_features_;
|
||||
|
||||
// These arrays are separated from their sizes to minimize padding on 64-bit.
|
||||
FieldDescriptor* fields_;
|
||||
OneofDescriptor* oneof_decls_;
|
||||
Descriptor* nested_types_;
|
||||
EnumDescriptor* enum_types_;
|
||||
ExtensionRange* extension_ranges_;
|
||||
FieldDescriptor* extensions_;
|
||||
ReservedRange* reserved_ranges_;
|
||||
const std::string** reserved_names_;
|
||||
internal::NonnullOffsetPtr<const FileDescriptor> file_;
|
||||
internal::NullableOffsetPtr<const Descriptor> containing_type_;
|
||||
internal::OffsetProtoPtr<const MessageOptions> options_;
|
||||
internal::NonnullOffsetPtr<FieldDescriptor> fields_;
|
||||
internal::NonnullOffsetPtr<OneofDescriptor> oneof_decls_;
|
||||
internal::NonnullOffsetPtr<Descriptor> nested_types_;
|
||||
internal::NonnullOffsetPtr<EnumDescriptor> enum_types_;
|
||||
internal::NonnullOffsetPtr<ExtensionRange> extension_ranges_;
|
||||
internal::NonnullOffsetPtr<FieldDescriptor> extensions_;
|
||||
internal::NonnullOffsetPtr<ReservedRange> reserved_ranges_;
|
||||
internal::NonnullOffsetPtr<const std::string*> reserved_names_;
|
||||
|
||||
int field_count_;
|
||||
int oneof_decl_count_;
|
||||
int real_oneof_decl_count_;
|
||||
int nested_type_count_;
|
||||
|
|
@ -850,6 +857,9 @@ class PROTOBUF_EXPORT Descriptor : private internal::SymbolBase {
|
|||
int reserved_range_count_;
|
||||
int reserved_name_count_;
|
||||
|
||||
const FeatureSet* proto_features_;
|
||||
const FeatureSet* merged_features_;
|
||||
|
||||
// IMPORTANT: If you add a new field, make sure to search for all instances
|
||||
// of Allocate<Descriptor>() and AllocateArray<Descriptor>() in descriptor.cc
|
||||
// and update them to initialize the field.
|
||||
|
|
@ -867,7 +877,8 @@ class PROTOBUF_EXPORT Descriptor : private internal::SymbolBase {
|
|||
friend class SymbolChecker;
|
||||
};
|
||||
|
||||
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(Descriptor, 160);
|
||||
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(Descriptor, 112);
|
||||
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(Descriptor::ExtensionRange, 40);
|
||||
|
||||
// Describes a single field of a message. To get the descriptor for a given
|
||||
// field, first get the Descriptor for the message in which it is defined,
|
||||
|
|
@ -1273,6 +1284,9 @@ class PROTOBUF_EXPORT FieldDescriptor : private internal::SymbolBase,
|
|||
|
||||
CppRepeatedType CalculateCppRepeatedType() const;
|
||||
|
||||
static void TypeOnceInit(const FieldDescriptor* to_init);
|
||||
void InternalTypeOnceInit() const;
|
||||
|
||||
bool has_default_value_ : 1;
|
||||
bool proto3_optional_ : 1;
|
||||
// Whether the user has specified the json_name field option in the .proto
|
||||
|
|
@ -1308,25 +1322,32 @@ class PROTOBUF_EXPORT FieldDescriptor : private internal::SymbolBase,
|
|||
// and its indices above.
|
||||
int number_;
|
||||
internal::DescriptorNames all_names_;
|
||||
const FileDescriptor* file_;
|
||||
internal::NonnullOffsetPtr<const FileDescriptor> file_;
|
||||
|
||||
union {
|
||||
internal::NonnullOffsetPtr<const OneofDescriptor> containing_oneof;
|
||||
internal::NullableOffsetPtr<const Descriptor> extension_scope;
|
||||
} scope_;
|
||||
|
||||
internal::OffsetProtoPtr<const FieldOptions> options_;
|
||||
|
||||
// The once_flag is followed by a NUL terminated string for the type name and
|
||||
// enum default value (or empty string if no default enum).
|
||||
// Allocated separately, so no OffsetPtr.
|
||||
absl::once_flag* type_once_;
|
||||
static void TypeOnceInit(const FieldDescriptor* to_init);
|
||||
void InternalTypeOnceInit() const;
|
||||
|
||||
// Extensions' containing type can be from a different file, so no OffsetPtr.
|
||||
const Descriptor* containing_type_;
|
||||
|
||||
union {
|
||||
const OneofDescriptor* containing_oneof;
|
||||
const Descriptor* extension_scope;
|
||||
} scope_;
|
||||
union {
|
||||
// Types can be from different files so no OffsetPtr.
|
||||
mutable const Descriptor* message_type;
|
||||
mutable const EnumDescriptor* enum_type;
|
||||
} type_descriptor_;
|
||||
const FieldOptions* options_;
|
||||
|
||||
const FeatureSet* proto_features_;
|
||||
const FeatureSet* merged_features_;
|
||||
|
||||
// IMPORTANT: If you add a new field, make sure to search for all instances
|
||||
// of Allocate<FieldDescriptor>() and AllocateArray<FieldDescriptor>() in
|
||||
// descriptor.cc and update them to initialize the field.
|
||||
|
|
@ -1362,7 +1383,7 @@ class PROTOBUF_EXPORT FieldDescriptor : private internal::SymbolBase,
|
|||
friend class OneofDescriptor;
|
||||
};
|
||||
|
||||
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(FieldDescriptor, 88);
|
||||
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(FieldDescriptor, 72);
|
||||
|
||||
// Describes a oneof defined in a message type.
|
||||
class PROTOBUF_EXPORT OneofDescriptor : private internal::SymbolBase {
|
||||
|
|
@ -1451,11 +1472,12 @@ class PROTOBUF_EXPORT OneofDescriptor : private internal::SymbolBase {
|
|||
int field_count_;
|
||||
|
||||
internal::DescriptorNames all_names_;
|
||||
const Descriptor* containing_type_;
|
||||
const OneofOptions* options_;
|
||||
internal::NonnullOffsetPtr<const Descriptor> containing_type_;
|
||||
internal::OffsetProtoPtr<const OneofOptions> options_;
|
||||
internal::NonnullOffsetPtr<const FieldDescriptor> fields_;
|
||||
|
||||
const FeatureSet* proto_features_;
|
||||
const FeatureSet* merged_features_;
|
||||
const FieldDescriptor* fields_;
|
||||
|
||||
// IMPORTANT: If you add a new field, make sure to search for all instances
|
||||
// of Allocate<OneofDescriptor>() and AllocateArray<OneofDescriptor>()
|
||||
|
|
@ -1469,7 +1491,7 @@ class PROTOBUF_EXPORT OneofDescriptor : private internal::SymbolBase {
|
|||
friend class Reflection;
|
||||
};
|
||||
|
||||
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(OneofDescriptor, 56);
|
||||
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(OneofDescriptor, 40);
|
||||
|
||||
// Describes an enum type defined in a .proto file. To get the EnumDescriptor
|
||||
// for a generated enum type, call TypeName_descriptor(). Use DescriptorPool
|
||||
|
|
@ -1663,20 +1685,20 @@ class PROTOBUF_EXPORT EnumDescriptor : private internal::SymbolBase {
|
|||
// sequentially numbered labels in an enum.
|
||||
int16_t sequential_value_limit_;
|
||||
|
||||
int value_count_;
|
||||
|
||||
internal::DescriptorNames all_names_;
|
||||
const FileDescriptor* file_;
|
||||
const Descriptor* containing_type_;
|
||||
const EnumOptions* options_;
|
||||
const FeatureSet* proto_features_;
|
||||
const FeatureSet* merged_features_;
|
||||
EnumValueDescriptor* values_;
|
||||
internal::NonnullOffsetPtr<const FileDescriptor> file_;
|
||||
internal::NullableOffsetPtr<const Descriptor> containing_type_;
|
||||
internal::OffsetProtoPtr<const EnumOptions> options_;
|
||||
internal::NonnullOffsetPtr<EnumValueDescriptor> values_;
|
||||
internal::NonnullOffsetPtr<EnumDescriptor::ReservedRange> reserved_ranges_;
|
||||
internal::NonnullOffsetPtr<const std::string*> reserved_names_;
|
||||
|
||||
int value_count_;
|
||||
int reserved_range_count_;
|
||||
int reserved_name_count_;
|
||||
EnumDescriptor::ReservedRange* reserved_ranges_;
|
||||
const std::string** reserved_names_;
|
||||
|
||||
const FeatureSet* proto_features_;
|
||||
const FeatureSet* merged_features_;
|
||||
|
||||
// IMPORTANT: If you add a new field, make sure to search for all instances
|
||||
// of Allocate<EnumDescriptor>() and AllocateArray<EnumDescriptor>() in
|
||||
|
|
@ -1694,7 +1716,7 @@ class PROTOBUF_EXPORT EnumDescriptor : private internal::SymbolBase {
|
|||
friend class Reflection;
|
||||
};
|
||||
|
||||
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(EnumDescriptor, 88);
|
||||
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(EnumDescriptor, 64);
|
||||
|
||||
// Describes an individual enum constant of a particular type. To get the
|
||||
// EnumValueDescriptor for a given enum value, first get the EnumDescriptor
|
||||
|
|
@ -1789,9 +1811,11 @@ class PROTOBUF_EXPORT EnumValueDescriptor : private internal::SymbolBaseN<0>,
|
|||
// We keep the old-style std::string payload to support `NameOfEnumAsString`
|
||||
// Once we start migrating Enum_Name functions to string_view we can switch
|
||||
// this too.
|
||||
const std::string* all_names_;
|
||||
internal::NonnullOffsetPtr<const std::string> all_names_;
|
||||
internal::OffsetProtoPtr<const EnumValueOptions> options_;
|
||||
// Type can be from a different allocation when creating enums via
|
||||
// `FindEnumValueByNumberCreatingIfUnknown`.
|
||||
const EnumDescriptor* type_;
|
||||
const EnumValueOptions* options_;
|
||||
const FeatureSet* proto_features_;
|
||||
const FeatureSet* merged_features_;
|
||||
// IMPORTANT: If you add a new field, make sure to search for all instances
|
||||
|
|
@ -1807,7 +1831,7 @@ class PROTOBUF_EXPORT EnumValueDescriptor : private internal::SymbolBaseN<0>,
|
|||
friend class Reflection;
|
||||
};
|
||||
|
||||
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(EnumValueDescriptor, 48);
|
||||
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(EnumValueDescriptor, 40);
|
||||
|
||||
// Describes an RPC service. Use DescriptorPool to construct your own
|
||||
// descriptors.
|
||||
|
|
@ -1897,12 +1921,14 @@ class PROTOBUF_EXPORT ServiceDescriptor : private internal::SymbolBase {
|
|||
void GetLocationPath(std::vector<int>* output) const;
|
||||
|
||||
internal::DescriptorNames all_names_;
|
||||
const FileDescriptor* file_;
|
||||
const ServiceOptions* options_;
|
||||
internal::NonnullOffsetPtr<const FileDescriptor> file_;
|
||||
internal::OffsetProtoPtr<const ServiceOptions> options_;
|
||||
internal::NonnullOffsetPtr<MethodDescriptor> methods_;
|
||||
int method_count_;
|
||||
|
||||
const FeatureSet* proto_features_;
|
||||
const FeatureSet* merged_features_;
|
||||
MethodDescriptor* methods_;
|
||||
int method_count_;
|
||||
|
||||
// IMPORTANT: If you add a new field, make sure to search for all instances
|
||||
// of Allocate<ServiceDescriptor>() and AllocateArray<ServiceDescriptor>() in
|
||||
// descriptor.cc and update them to initialize the field.
|
||||
|
|
@ -1914,7 +1940,7 @@ class PROTOBUF_EXPORT ServiceDescriptor : private internal::SymbolBase {
|
|||
friend class MethodDescriptor;
|
||||
};
|
||||
|
||||
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(ServiceDescriptor, 64);
|
||||
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(ServiceDescriptor, 40);
|
||||
|
||||
// Describes an individual service method. To obtain a MethodDescriptor given
|
||||
// a service, first get its ServiceDescriptor, then call
|
||||
|
|
@ -2007,10 +2033,13 @@ class PROTOBUF_EXPORT MethodDescriptor : private internal::SymbolBase {
|
|||
bool client_streaming_;
|
||||
bool server_streaming_;
|
||||
internal::DescriptorNames all_names_;
|
||||
const ServiceDescriptor* service_;
|
||||
internal::NonnullOffsetPtr<const ServiceDescriptor> service_;
|
||||
|
||||
internal::OffsetProtoPtr<const MethodOptions> options_;
|
||||
|
||||
mutable internal::LazyDescriptor input_type_;
|
||||
mutable internal::LazyDescriptor output_type_;
|
||||
const MethodOptions* options_;
|
||||
|
||||
const FeatureSet* proto_features_;
|
||||
const FeatureSet* merged_features_;
|
||||
// IMPORTANT: If you add a new field, make sure to search for all instances
|
||||
|
|
@ -2023,7 +2052,7 @@ class PROTOBUF_EXPORT MethodDescriptor : private internal::SymbolBase {
|
|||
friend class ServiceDescriptor;
|
||||
};
|
||||
|
||||
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(MethodDescriptor, 80);
|
||||
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(MethodDescriptor, 64);
|
||||
|
||||
// Describes a whole .proto file. To get the FileDescriptor for a compiled-in
|
||||
// file, get the descriptor for something defined in that file and call
|
||||
|
|
@ -2199,19 +2228,6 @@ class PROTOBUF_EXPORT FileDescriptor : private internal::SymbolBase {
|
|||
friend class FileDescriptorLegacy;
|
||||
typedef FileOptions OptionsType;
|
||||
|
||||
bool is_placeholder_;
|
||||
// Indicates the FileDescriptor is completed building. Used to verify
|
||||
// that type accessor functions that can possibly build a dependent file
|
||||
// aren't called during the process of building the file.
|
||||
bool finished_building_;
|
||||
// This one is here to fill the padding.
|
||||
int extension_count_;
|
||||
|
||||
const std::string* name_;
|
||||
const std::string* package_;
|
||||
const DescriptorPool* pool_;
|
||||
Edition edition_;
|
||||
|
||||
// Returns edition of this file. For legacy proto2/proto3 files, special
|
||||
// EDITION_PROTO2 and EDITION_PROTO3 values are used.
|
||||
Edition edition() const;
|
||||
|
|
@ -2223,12 +2239,16 @@ class PROTOBUF_EXPORT FileDescriptor : private internal::SymbolBase {
|
|||
const FeatureSet& features() const { return *merged_features_; }
|
||||
friend class internal::InternalFeatureHelper;
|
||||
|
||||
// dependencies_once_ contain a once_flag followed by N NUL terminated
|
||||
// strings. Dependencies that do not need to be loaded will be empty. ie just
|
||||
// {'\0'}
|
||||
absl::once_flag* dependencies_once_;
|
||||
static void DependenciesOnceInit(const FileDescriptor* to_init);
|
||||
void InternalDependenciesOnceInit() const;
|
||||
bool is_placeholder_;
|
||||
// Indicates the FileDescriptor is completed building. Used to verify
|
||||
// that type accessor functions that can possibly build a dependent file
|
||||
// aren't called during the process of building the file.
|
||||
bool finished_building_;
|
||||
// This one is here to fill the padding.
|
||||
int extension_count_;
|
||||
|
||||
internal::NonnullOffsetPtr<const std::string> name_;
|
||||
Edition edition_;
|
||||
|
||||
// These are arranged to minimize padding on 64-bit.
|
||||
int dependency_count_;
|
||||
|
|
@ -2239,21 +2259,34 @@ class PROTOBUF_EXPORT FileDescriptor : private internal::SymbolBase {
|
|||
int enum_type_count_;
|
||||
int service_count_;
|
||||
|
||||
mutable const FileDescriptor** dependencies_;
|
||||
int* public_dependencies_;
|
||||
int* weak_dependencies_;
|
||||
absl::string_view* option_dependencies_;
|
||||
internal::NonnullOffsetPtr<const FileDescriptor*> dependencies_;
|
||||
internal::NonnullOffsetPtr<int> public_dependencies_;
|
||||
internal::NonnullOffsetPtr<int> weak_dependencies_;
|
||||
internal::NonnullOffsetPtr<absl::string_view> option_dependencies_;
|
||||
|
||||
internal::NonnullOffsetPtr<Descriptor> message_types_;
|
||||
internal::NonnullOffsetPtr<EnumDescriptor> enum_types_;
|
||||
internal::NonnullOffsetPtr<ServiceDescriptor> services_;
|
||||
internal::NonnullOffsetPtr<FieldDescriptor> extensions_;
|
||||
internal::OffsetProtoPtr<const FileOptions> options_;
|
||||
|
||||
internal::OffsetProtoPtr<const SourceCodeInfo> source_code_info_;
|
||||
|
||||
const std::string* package_;
|
||||
|
||||
// dependencies_once_ contain a once_flag followed by N NUL terminated
|
||||
// strings. Dependencies that do not need to be loaded will be empty. ie just
|
||||
// {'\0'}
|
||||
absl::once_flag* dependencies_once_;
|
||||
static void DependenciesOnceInit(const FileDescriptor* to_init);
|
||||
void InternalDependenciesOnceInit() const;
|
||||
|
||||
const DescriptorPool* pool_;
|
||||
|
||||
Descriptor* message_types_;
|
||||
EnumDescriptor* enum_types_;
|
||||
ServiceDescriptor* services_;
|
||||
FieldDescriptor* extensions_;
|
||||
const FileOptions* options_;
|
||||
const FeatureSet* proto_features_;
|
||||
const FeatureSet* merged_features_;
|
||||
|
||||
const FileDescriptorTables* tables_;
|
||||
const SourceCodeInfo* source_code_info_;
|
||||
|
||||
// IMPORTANT: If you add a new field, make sure to search for all instances
|
||||
// of Allocate<FileDescriptor>() and AllocateArray<FileDescriptor>() in
|
||||
|
|
@ -2272,7 +2305,7 @@ class PROTOBUF_EXPORT FileDescriptor : private internal::SymbolBase {
|
|||
friend class ServiceDescriptor;
|
||||
};
|
||||
|
||||
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(FileDescriptor, 184);
|
||||
PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(FileDescriptor, 136);
|
||||
|
||||
#ifndef SWIG
|
||||
enum class ExtDeclEnforcementLevel : uint8_t {
|
||||
|
|
@ -2903,9 +2936,6 @@ class PROTOBUF_EXPORT DescriptorPool {
|
|||
return FIELD##s_ + index; \
|
||||
}
|
||||
|
||||
#define PROTOBUF_DEFINE_OPTIONS_ACCESSOR(CLASS, TYPE) \
|
||||
inline const TYPE& CLASS::options() const { return *options_; }
|
||||
|
||||
PROTOBUF_DEFINE_NAME_ACCESSOR(Descriptor)
|
||||
PROTOBUF_DEFINE_ACCESSOR(Descriptor, file, const FileDescriptor*)
|
||||
PROTOBUF_DEFINE_ACCESSOR(Descriptor, containing_type, const Descriptor*)
|
||||
|
|
@ -2936,7 +2966,6 @@ PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, reserved_range,
|
|||
const Descriptor::ReservedRange*)
|
||||
PROTOBUF_DEFINE_ACCESSOR(Descriptor, reserved_name_count, int)
|
||||
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions)
|
||||
PROTOBUF_DEFINE_ACCESSOR(Descriptor, is_placeholder, bool)
|
||||
|
||||
PROTOBUF_DEFINE_NAME_ACCESSOR(FieldDescriptor)
|
||||
|
|
@ -2944,7 +2973,6 @@ PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, file, const FileDescriptor*)
|
|||
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, number, int)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, is_extension, bool)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, containing_type, const Descriptor*)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FieldDescriptor, FieldOptions)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_default_value, bool)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_json_name, bool)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int32_t, int32_t)
|
||||
|
|
@ -2960,7 +2988,6 @@ PROTOBUF_DEFINE_NAME_ACCESSOR(OneofDescriptor)
|
|||
PROTOBUF_DEFINE_ACCESSOR(OneofDescriptor, containing_type, const Descriptor*)
|
||||
PROTOBUF_DEFINE_ACCESSOR(OneofDescriptor, field_count, int)
|
||||
PROTOBUF_DEFINE_ARRAY_ACCESSOR(OneofDescriptor, field, const FieldDescriptor*)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(OneofDescriptor, OneofOptions)
|
||||
|
||||
PROTOBUF_DEFINE_NAME_ACCESSOR(EnumDescriptor)
|
||||
PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, file, const FileDescriptor*)
|
||||
|
|
@ -2968,7 +2995,6 @@ PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, containing_type, const Descriptor*)
|
|||
PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, value_count, int)
|
||||
PROTOBUF_DEFINE_ARRAY_ACCESSOR(EnumDescriptor, value,
|
||||
const EnumValueDescriptor*)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions)
|
||||
PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, is_placeholder, bool)
|
||||
PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, reserved_range_count, int)
|
||||
PROTOBUF_DEFINE_ARRAY_ACCESSOR(EnumDescriptor, reserved_range,
|
||||
|
|
@ -2983,18 +3009,15 @@ inline absl::string_view EnumValueDescriptor::full_name() const {
|
|||
}
|
||||
PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, number, int)
|
||||
PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, type, const EnumDescriptor*)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumValueDescriptor, EnumValueOptions)
|
||||
|
||||
PROTOBUF_DEFINE_NAME_ACCESSOR(ServiceDescriptor)
|
||||
PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, file, const FileDescriptor*)
|
||||
PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, method_count, int)
|
||||
PROTOBUF_DEFINE_ARRAY_ACCESSOR(ServiceDescriptor, method,
|
||||
const MethodDescriptor*)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions)
|
||||
|
||||
PROTOBUF_DEFINE_NAME_ACCESSOR(MethodDescriptor)
|
||||
PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, service, const ServiceDescriptor*)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions)
|
||||
PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, client_streaming, bool)
|
||||
PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, server_streaming, bool)
|
||||
|
||||
|
|
@ -3009,7 +3032,6 @@ PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, message_type_count, int)
|
|||
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, enum_type_count, int)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, service_count, int)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, extension_count, int)
|
||||
PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions)
|
||||
PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, is_placeholder, bool)
|
||||
|
||||
PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, message_type, const Descriptor*)
|
||||
|
|
@ -3085,7 +3107,7 @@ inline absl::string_view FieldDescriptor::json_name() const {
|
|||
|
||||
inline const OneofDescriptor* FieldDescriptor::containing_oneof() const {
|
||||
if (is_oneof_) {
|
||||
auto* res = scope_.containing_oneof;
|
||||
const OneofDescriptor* res = scope_.containing_oneof;
|
||||
PROTOBUF_ASSUME(res != nullptr);
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1372,7 +1372,7 @@ inline void* PROTOBUF_NONNULL FeatureSet::PlacementNew_(
|
|||
return ::new (mem) FeatureSet(arena);
|
||||
}
|
||||
constexpr auto FeatureSet::InternalNewImpl_() {
|
||||
return ::google::protobuf::internal::MessageCreator::ZeroInit(sizeof(FeatureSet), alignof(FeatureSet));
|
||||
return ::google::protobuf::internal::MessageCreator::CopyInit(sizeof(FeatureSet), alignof(FeatureSet));
|
||||
}
|
||||
constexpr auto FeatureSet::InternalGenerateClassData_(
|
||||
const MessageLite& prototype,
|
||||
|
|
|
|||
|
|
@ -16361,114 +16361,7 @@ TEST_F(SourceLocationTest, GetSourceLocation) {
|
|||
"rpc Method(A) returns (A.B);"));
|
||||
}
|
||||
|
||||
TEST_F(SourceLocationTest, AggregateOptionSourceLocation) {
|
||||
SourceLocation loc;
|
||||
const FileDescriptor* file_desc =
|
||||
ABSL_DIE_IF_NULL(pool_.FindFileByName("/test/test.proto"));
|
||||
|
||||
SourceCodePath base_path = {FileDescriptorProto::kServiceFieldNumber,
|
||||
0,
|
||||
ServiceDescriptorProto::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber,
|
||||
0,
|
||||
UninterpretedOption::kAggregateValueFieldNumber};
|
||||
|
||||
auto make_path = [&](std::initializer_list<int> sub) {
|
||||
SourceCodePath path = base_path;
|
||||
path.insert(path.end(), sub.begin(), sub.end());
|
||||
return path;
|
||||
};
|
||||
|
||||
// Verify what base_path matches directly (the entire aggregate block).
|
||||
{
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(base_path, &loc));
|
||||
EXPECT_THAT(loc,
|
||||
MatchesSubstring(kSourceLocationTestInput,
|
||||
"{a:100, rep: [1, 2, 3], b_sub: {b: 200}}"));
|
||||
}
|
||||
|
||||
// Path to "a" inside {a:100}
|
||||
{
|
||||
SourceCodePath path =
|
||||
make_path({kAFieldNumber, UninterpretedOption::kNameFieldNumber});
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
|
||||
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "a"));
|
||||
}
|
||||
|
||||
// Path to "100" inside {a:100}
|
||||
{
|
||||
SourceCodePath path = make_path(
|
||||
{kAFieldNumber, UninterpretedOption::kPositiveIntValueFieldNumber});
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
|
||||
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "100"));
|
||||
}
|
||||
|
||||
// Path to the name of the top-level option (test_svc_opt)
|
||||
{
|
||||
SourceCodePath path = {FileDescriptorProto::kServiceFieldNumber,
|
||||
0,
|
||||
ServiceDescriptorProto::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber,
|
||||
0,
|
||||
UninterpretedOption::kNameFieldNumber};
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
|
||||
EXPECT_THAT(loc,
|
||||
MatchesSubstring(kSourceLocationTestInput, "(test_svc_opt)"));
|
||||
}
|
||||
|
||||
// Path to "1" inside {rep: [1, 2, 3]}
|
||||
{
|
||||
SourceCodePath path =
|
||||
make_path({kRepFieldNumber, 0,
|
||||
UninterpretedOption::kPositiveIntValueFieldNumber});
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
|
||||
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "1"));
|
||||
}
|
||||
|
||||
// Path to "2" inside {rep: [1, 2, 3]}
|
||||
{
|
||||
SourceCodePath path =
|
||||
make_path({kRepFieldNumber, 1,
|
||||
UninterpretedOption::kPositiveIntValueFieldNumber});
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
|
||||
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "2"));
|
||||
}
|
||||
|
||||
// Path to "3" inside {rep: [1, 2, 3]}
|
||||
{
|
||||
SourceCodePath path =
|
||||
make_path({kRepFieldNumber, 2,
|
||||
UninterpretedOption::kPositiveIntValueFieldNumber});
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
|
||||
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "3"));
|
||||
}
|
||||
|
||||
// Path to "b_sub" inside {..., b_sub: {b: 200}}
|
||||
{
|
||||
SourceCodePath path =
|
||||
make_path({kBSubFieldNumber, UninterpretedOption::kNameFieldNumber});
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
|
||||
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "b_sub"));
|
||||
}
|
||||
|
||||
// Path to "b" inside {..., b_sub: {b: 200}}
|
||||
{
|
||||
SourceCodePath path = make_path(
|
||||
{kBSubFieldNumber, UninterpretedOption::kAggregateValueFieldNumber,
|
||||
kBFieldNumber, UninterpretedOption::kNameFieldNumber});
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
|
||||
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "b"));
|
||||
}
|
||||
|
||||
// Path to "200" inside {..., b_sub: {b: 200}}
|
||||
{
|
||||
SourceCodePath path = make_path(
|
||||
{kBSubFieldNumber, UninterpretedOption::kAggregateValueFieldNumber,
|
||||
kBFieldNumber, UninterpretedOption::kDoubleValueFieldNumber});
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(path, &loc));
|
||||
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "200"));
|
||||
}
|
||||
}
|
||||
// TODO: b/168903973 - Remove once we update the format.
|
||||
|
||||
TEST_F(SourceLocationTest, ExtensionSourceLocation) {
|
||||
SourceLocation loc;
|
||||
|
|
@ -16526,19 +16419,7 @@ TEST_F(SourceLocationTest, InterpretedOptionSourceLocation) {
|
|||
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(unint, &loc));
|
||||
|
||||
SourceCodePath name_path = {FileDescriptorProto::kOptionsFieldNumber,
|
||||
FileOptions::kJavaPackageFieldNumber,
|
||||
UninterpretedOption::kNameFieldNumber};
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(name_path, &loc));
|
||||
EXPECT_THAT(loc,
|
||||
MatchesSubstring(kSourceLocationTestInput, "java_package"));
|
||||
|
||||
SourceCodePath val_path = {FileDescriptorProto::kOptionsFieldNumber,
|
||||
FileOptions::kJavaPackageFieldNumber,
|
||||
UninterpretedOption::kStringValueFieldNumber};
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(val_path, &loc));
|
||||
EXPECT_THAT(loc,
|
||||
MatchesSubstring(kSourceLocationTestInput, "\"com.foo.bar\""));
|
||||
// TODO: b/168903973 - Remove once we update the format.
|
||||
}
|
||||
{
|
||||
SourceCodePath path = {FileDescriptorProto::kOptionsFieldNumber,
|
||||
|
|
@ -16551,18 +16432,7 @@ TEST_F(SourceLocationTest, InterpretedOptionSourceLocation) {
|
|||
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(unint, &loc));
|
||||
|
||||
SourceCodePath name_path = {FileDescriptorProto::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber,
|
||||
UninterpretedOption::kNameFieldNumber};
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(name_path, &loc));
|
||||
EXPECT_THAT(loc,
|
||||
MatchesSubstring(kSourceLocationTestInput, "(test_file_opt)"));
|
||||
|
||||
SourceCodePath val_path = {FileDescriptorProto::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber,
|
||||
UninterpretedOption::kStringValueFieldNumber};
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(val_path, &loc));
|
||||
EXPECT_THAT(loc, MatchesSubstring(kSourceLocationTestInput, "\"foobar\""));
|
||||
// TODO: b/168903973 - Remove once we update the format.
|
||||
}
|
||||
|
||||
// Message option
|
||||
|
|
|
|||
|
|
@ -185,39 +185,46 @@ void ExtensionSet::RegisterMessageExtension(const MessageLite* extendee,
|
|||
// ===================================================================
|
||||
// Constructors and basic methods.
|
||||
|
||||
constexpr ExtensionSet::FlatItem ExtensionSet::kEmptyKeyValue = {0, 0, 0,
|
||||
Extension()};
|
||||
|
||||
ExtensionSet::~ExtensionSet() {
|
||||
// Deletes all allocated extensions.
|
||||
|
||||
if (IsCompletelyEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ForEach([](int /* number */, Extension& ext) { ext.Free(); }, PrefetchNta{});
|
||||
if (ABSL_PREDICT_FALSE(is_large())) {
|
||||
delete map_.large;
|
||||
} else {
|
||||
DeleteFlatMap(map_.flat, flat_capacity_);
|
||||
DeleteFlatMap(map_.flat, flat_capacity());
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionSet::KeyValue* ExtensionSet::AllocateFlatMap(
|
||||
ExtensionSet::FlatItem* ExtensionSet::AllocateFlatMap(
|
||||
Arena* arena, uint16_t powerof2_flat_capacity) {
|
||||
// It is important to allocate power-of-2 bytes in order to reuse
|
||||
// allocated blocks in arena for ExtensionSet and RepeatedFields.
|
||||
// ReturnArrayMemory is also more efficient with power-of-2 bytes, and
|
||||
// sizeof(KeyValue) is a power-of-2 on 64-bit platforms.
|
||||
static_assert(absl::has_single_bit(sizeof(KeyValue)) || sizeof(void*) != 8,
|
||||
static_assert(absl::has_single_bit(sizeof(FlatItem)) || sizeof(void*) != 8,
|
||||
"sizeof(KeyValue) must be a power of 2");
|
||||
ABSL_DCHECK(absl::has_single_bit(powerof2_flat_capacity));
|
||||
return Arena::CreateArray<ExtensionSet::KeyValue>(arena,
|
||||
return Arena::CreateArray<ExtensionSet::FlatItem>(arena,
|
||||
powerof2_flat_capacity);
|
||||
}
|
||||
|
||||
void ExtensionSet::DeleteFlatMap(const ExtensionSet::KeyValue* flat,
|
||||
void ExtensionSet::DeleteFlatMap(const ExtensionSet::FlatItem* flat,
|
||||
uint16_t flat_capacity) {
|
||||
// Arena::CreateArray already requires a trivially destructible type, but
|
||||
// ensure this constraint is not violated in the future.
|
||||
static_assert(std::is_trivially_destructible_v<KeyValue>,
|
||||
static_assert(std::is_trivially_destructible_v<FlatItem>,
|
||||
"CreateArray requires a trivially destructible type");
|
||||
// A const-cast is needed, but this is safe as we are about to deallocate the
|
||||
// array.
|
||||
internal::SizedArrayDelete(const_cast<KeyValue*>(flat),
|
||||
internal::SizedArrayDelete(const_cast<FlatItem*>(flat),
|
||||
sizeof(*flat) * flat_capacity);
|
||||
}
|
||||
|
||||
|
|
@ -794,21 +801,23 @@ void ExtensionSet::MergeFrom(Arena* arena, const MessageLite* extendee,
|
|||
|
||||
ABSL_ATTRIBUTE_NOINLINE void ExtensionSet::InternalReduceSmallCapacity(
|
||||
Arena* arena) {
|
||||
ABSL_DCHECK_LE(flat_size_, kMaximumFlatCapacity);
|
||||
ABSL_DCHECK_LE(flat_capacity_, kMaximumFlatCapacity);
|
||||
ABSL_DCHECK_GT(flat_size_, 0);
|
||||
ABSL_DCHECK_GE(flat_capacity_, flat_size_ * 2);
|
||||
const size_t new_flat_capacity = absl::bit_ceil(flat_size_);
|
||||
uint16_t current_size = flat_size();
|
||||
uint16_t current_cap = flat_capacity();
|
||||
ABSL_DCHECK_LE(current_size, kMaximumFlatCapacity);
|
||||
ABSL_DCHECK_LE(current_cap, kMaximumFlatCapacity);
|
||||
ABSL_DCHECK_GT(current_size, 0);
|
||||
ABSL_DCHECK_GE(current_cap, current_size * 2);
|
||||
const size_t new_flat_capacity = absl::bit_ceil(current_size);
|
||||
auto* new_flat = AllocateFlatMap(arena, new_flat_capacity);
|
||||
std::memcpy(new_flat, map_.flat, flat_size_ * sizeof(KeyValue));
|
||||
std::memcpy(new_flat, map_.flat, current_size * sizeof(FlatItem));
|
||||
auto* old_flat = map_.flat;
|
||||
if (arena == nullptr) {
|
||||
DeleteFlatMap(old_flat, flat_capacity_);
|
||||
DeleteFlatMap(old_flat, current_cap);
|
||||
} else {
|
||||
arena->ReturnArrayMemory(old_flat, sizeof(KeyValue) * flat_capacity_);
|
||||
arena->ReturnArrayMemory(old_flat, sizeof(FlatItem) * current_cap);
|
||||
}
|
||||
map_.flat = new_flat;
|
||||
flat_capacity_ = new_flat_capacity;
|
||||
set_flat_capacity_and_size(new_flat_capacity, current_size);
|
||||
}
|
||||
|
||||
void ExtensionSet::InternalMergeFromSmallToEmpty(Arena* arena,
|
||||
|
|
@ -816,24 +825,22 @@ void ExtensionSet::InternalMergeFromSmallToEmpty(Arena* arena,
|
|||
const ExtensionSet& other,
|
||||
Arena* other_arena) {
|
||||
ABSL_DCHECK(!other.is_large());
|
||||
// Compiler is complaining on potential side effects for `!other.is_large()`.
|
||||
ABSL_ASSUME(static_cast<int16_t>(flat_size_) >= 0);
|
||||
ABSL_DCHECK(IsCompletelyEmpty());
|
||||
|
||||
if (other.flat_size_ == 0) {
|
||||
uint16_t new_size = other.flat_size();
|
||||
if (new_size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
flat_size_ = other.flat_size_;
|
||||
KeyValue* dst_it = nullptr;
|
||||
PROTOBUF_ASSUME(static_cast<int16_t>(new_size) > 0);
|
||||
FlatItem* dst_it = nullptr;
|
||||
other.ForEach(
|
||||
[&](int number, const Extension& ext) {
|
||||
if (ext.is_cleared) {
|
||||
--flat_size_;
|
||||
--new_size;
|
||||
return;
|
||||
}
|
||||
if (dst_it == nullptr) {
|
||||
InternalReserveSmallCapacityFromEmpty(arena, flat_size_);
|
||||
InternalReserveSmallCapacityFromEmpty(arena, new_size);
|
||||
dst_it = map_.flat;
|
||||
}
|
||||
dst_it->first = number;
|
||||
|
|
@ -842,10 +849,11 @@ void ExtensionSet::InternalMergeFromSmallToEmpty(Arena* arena,
|
|||
++dst_it;
|
||||
},
|
||||
Prefetch{});
|
||||
if (flat_capacity_ == 0) {
|
||||
if (new_size == 0) {
|
||||
return;
|
||||
}
|
||||
if (ABSL_PREDICT_FALSE(flat_capacity_ >= flat_size_ * 2)) {
|
||||
set_flat_size(new_size);
|
||||
if (ABSL_PREDICT_FALSE(flat_capacity() >= new_size * 2)) {
|
||||
InternalReduceSmallCapacity(arena);
|
||||
}
|
||||
}
|
||||
|
|
@ -860,8 +868,8 @@ void ExtensionSet::InternalMergeFromSlow(Arena* arena,
|
|||
other.flat_begin(), other.flat_end()));
|
||||
} else {
|
||||
GrowCapacity(arena, SizeOfUnion(flat_begin(), flat_end(),
|
||||
other.map_.large->begin(),
|
||||
other.map_.large->end()));
|
||||
other.map_.large->large.begin(),
|
||||
other.map_.large->large.end()));
|
||||
}
|
||||
}
|
||||
other.ForEach(
|
||||
|
|
@ -940,6 +948,9 @@ void ExtensionSet::InternalExtensionMergeFrom(Arena* arena,
|
|||
int number,
|
||||
const Extension& other_extension,
|
||||
Arena* other_arena) {
|
||||
if (other_extension.is_cleared) {
|
||||
return;
|
||||
}
|
||||
Extension* dst_extension;
|
||||
bool is_new = MaybeNewExtension(arena, number, other_extension.descriptor,
|
||||
&dst_extension);
|
||||
|
|
@ -975,9 +986,6 @@ void ExtensionSet::InternalExtensionMergeFrom(Arena* arena,
|
|||
return;
|
||||
}
|
||||
|
||||
if (other_extension.is_cleared) {
|
||||
return;
|
||||
}
|
||||
dst_extension->is_cleared = false;
|
||||
switch (cpp_type(other_extension.type)) {
|
||||
#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
|
||||
|
|
@ -1036,8 +1044,6 @@ void ExtensionSet::Swap(Arena* arena, const MessageLite* extendee,
|
|||
|
||||
void ExtensionSet::InternalSwap(ExtensionSet* other) {
|
||||
using std::swap;
|
||||
swap(flat_capacity_, other->flat_capacity_);
|
||||
swap(flat_size_, other->flat_size_);
|
||||
swap(map_, other->map_);
|
||||
}
|
||||
|
||||
|
|
@ -1111,14 +1117,14 @@ bool ExtensionSet::IsInitialized(Arena* arena,
|
|||
// Extensions are never required. However, we need to check that all
|
||||
// embedded messages are initialized.
|
||||
if (ABSL_PREDICT_FALSE(is_large())) {
|
||||
for (const auto& kv : *map_.large) {
|
||||
for (const auto& kv : map_.large->large) {
|
||||
if (!kv.second.IsInitialized(this, extendee, kv.first, arena)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
for (const KeyValue* it = flat_begin(); it != flat_end(); ++it) {
|
||||
for (const FlatItem* it = flat_begin(); it != flat_end(); ++it) {
|
||||
if (!it->second.IsInitialized(this, extendee, it->first, arena)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1164,8 +1170,8 @@ uint8_t* ExtensionSet::_InternalSerializeImpl(
|
|||
return _InternalSerializeImplLarge(extendee, start_field_number,
|
||||
end_field_number, target, stream);
|
||||
}
|
||||
const KeyValue* end = flat_end();
|
||||
const KeyValue* it = flat_begin();
|
||||
const FlatItem* end = flat_end();
|
||||
const FlatItem* it = flat_begin();
|
||||
while (it != end && it->first < start_field_number) ++it;
|
||||
for (; it != end && it->first < end_field_number; ++it) {
|
||||
target = it->second.InternalSerializeFieldWithCachedSizesToArray(
|
||||
|
|
@ -1190,8 +1196,8 @@ uint8_t* ExtensionSet::_InternalSerializeImplLarge(
|
|||
const MessageLite* extendee, int start_field_number, int end_field_number,
|
||||
uint8_t* target, io::EpsCopyOutputStream* stream) const {
|
||||
assert(is_large());
|
||||
const auto& end = map_.large->end();
|
||||
for (auto it = map_.large->lower_bound(start_field_number);
|
||||
const auto& end = map_.large->large.end();
|
||||
for (auto it = map_.large->large.lower_bound(start_field_number);
|
||||
it != end && it->first < end_field_number; ++it) {
|
||||
target = it->second.InternalSerializeFieldWithCachedSizesToArray(
|
||||
extendee, this, it->first, target, stream);
|
||||
|
|
@ -1526,7 +1532,7 @@ bool ExtensionSet::Extension::IsInitialized(const ExtensionSet* ext_set,
|
|||
|
||||
|
||||
const ExtensionSet::Extension* ExtensionSet::FindOrNull(int key) const {
|
||||
if (flat_size_ == 0) {
|
||||
if (IsCompletelyEmpty()) {
|
||||
return nullptr;
|
||||
} else if (ABSL_PREDICT_TRUE(!is_large())) {
|
||||
for (auto it = flat_begin(), end = flat_end();
|
||||
|
|
@ -1542,8 +1548,8 @@ const ExtensionSet::Extension* ExtensionSet::FindOrNull(int key) const {
|
|||
const ExtensionSet::Extension* ExtensionSet::FindOrNullInLargeMap(
|
||||
int key) const {
|
||||
assert(is_large());
|
||||
LargeMap::const_iterator it = map_.large->find(key);
|
||||
if (it != map_.large->end()) {
|
||||
LargeMap::const_iterator it = map_.large->large.find(key);
|
||||
if (it != map_.large->large.end()) {
|
||||
return &it->second;
|
||||
}
|
||||
return nullptr;
|
||||
|
|
@ -1564,17 +1570,27 @@ ABSL_ATTRIBUTE_NOINLINE
|
|||
std::pair<ExtensionSet::Extension*, bool>
|
||||
ExtensionSet::InternalInsertIntoLargeMap(int key) {
|
||||
ABSL_DCHECK(is_large());
|
||||
auto maybe = map_.large->insert({key, Extension()});
|
||||
auto maybe = map_.large->large.insert({key, Extension()});
|
||||
return {&maybe.first->second, maybe.second};
|
||||
}
|
||||
|
||||
std::pair<ExtensionSet::Extension*, bool> ExtensionSet::Insert(Arena* arena,
|
||||
int key) {
|
||||
if (IsCompletelyEmpty()) {
|
||||
map_.flat = AllocateFlatMap(arena, 1);
|
||||
map_.flat[0] = FlatItem{/*first=*/key,
|
||||
/*flat_capacity=*/1,
|
||||
/*flat_size=*/1,
|
||||
/*second=*/Extension()};
|
||||
return {&map_.flat[0].second, true};
|
||||
}
|
||||
if (ABSL_PREDICT_FALSE(is_large())) {
|
||||
return InternalInsertIntoLargeMap(key);
|
||||
}
|
||||
uint16_t i = flat_size_;
|
||||
KeyValue* flat = map_.flat;
|
||||
uint16_t current_size = flat_size();
|
||||
uint16_t current_cap = flat_capacity();
|
||||
uint16_t i = current_size;
|
||||
FlatItem* flat = map_.flat;
|
||||
// Iterating from the back to benefit the case where the keys are inserted in
|
||||
// increasing order.
|
||||
for (; i > 0; --i) {
|
||||
|
|
@ -1586,18 +1602,19 @@ std::pair<ExtensionSet::Extension*, bool> ExtensionSet::Insert(Arena* arena,
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (flat_size_ == flat_capacity_) {
|
||||
GrowCapacity(arena, flat_size_ + 1);
|
||||
if (current_size == current_cap) {
|
||||
GrowCapacity(arena, current_size + 1);
|
||||
if (ABSL_PREDICT_FALSE(is_large())) {
|
||||
return InternalInsertIntoLargeMap(key);
|
||||
}
|
||||
flat = map_.flat; // Reload flat pointer after GrowCapacity.
|
||||
current_cap = flat_capacity();
|
||||
}
|
||||
|
||||
std::copy_backward(flat + i, flat + flat_size_, flat + flat_size_ + 1);
|
||||
++flat_size_;
|
||||
std::copy_backward(flat + i, flat + current_size, flat + current_size + 1);
|
||||
flat[i].first = key;
|
||||
flat[i].second = Extension();
|
||||
set_flat_capacity_and_size(current_cap, current_size + 1);
|
||||
return {&flat[i].second, true};
|
||||
}
|
||||
|
||||
|
|
@ -1605,62 +1622,66 @@ void ExtensionSet::GrowCapacity(Arena* arena, size_t minimum_new_capacity) {
|
|||
if (ABSL_PREDICT_FALSE(is_large())) {
|
||||
return; // LargeMap does not have a "reserve" method.
|
||||
}
|
||||
if (flat_capacity_ >= minimum_new_capacity) {
|
||||
uint16_t current_cap = flat_capacity();
|
||||
if (current_cap >= minimum_new_capacity) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto new_flat_capacity = flat_capacity_;
|
||||
size_t new_flat_capacity = current_cap;
|
||||
do {
|
||||
new_flat_capacity = new_flat_capacity == 0 ? 1 : new_flat_capacity * 4;
|
||||
new_flat_capacity = new_flat_capacity == 0 ? 1 : new_flat_capacity * 2;
|
||||
} while (new_flat_capacity < minimum_new_capacity);
|
||||
|
||||
KeyValue* begin = flat_begin();
|
||||
KeyValue* end = flat_end();
|
||||
FlatItem* begin = flat_begin();
|
||||
FlatItem* end = flat_end();
|
||||
uint16_t current_size = flat_size();
|
||||
AllocatedData new_map;
|
||||
if (new_flat_capacity > kMaximumFlatCapacity) {
|
||||
new_map.large = Arena::Create<LargeMap>(arena);
|
||||
LargeMap::iterator hint = new_map.large->begin();
|
||||
for (const KeyValue* it = begin; it != end; ++it) {
|
||||
hint = new_map.large->insert(hint, {it->first, it->second});
|
||||
LargeRep* large_rep = Arena::Create<LargeRep>(arena);
|
||||
LargeMap::iterator hint = large_rep->large.begin();
|
||||
for (const FlatItem* it = begin; it != end; ++it) {
|
||||
hint = large_rep->large.insert(hint, {it->first, it->second});
|
||||
}
|
||||
flat_size_ = static_cast<uint16_t>(-1);
|
||||
ABSL_DCHECK(is_large());
|
||||
new_map.large = large_rep;
|
||||
} else {
|
||||
new_map.flat = AllocateFlatMap(arena, new_flat_capacity);
|
||||
std::copy(begin, end, new_map.flat);
|
||||
SetFlatCapacityAndSize(*new_map.flat, new_flat_capacity, current_size);
|
||||
}
|
||||
|
||||
if (flat_capacity_ > 0) {
|
||||
if (current_cap > 0) {
|
||||
if (arena == nullptr) {
|
||||
DeleteFlatMap(begin, flat_capacity_);
|
||||
DeleteFlatMap(begin, current_cap);
|
||||
} else {
|
||||
arena->ReturnArrayMemory(begin, sizeof(KeyValue) * flat_capacity_);
|
||||
arena->ReturnArrayMemory(begin, sizeof(FlatItem) * current_cap);
|
||||
}
|
||||
}
|
||||
flat_capacity_ = new_flat_capacity;
|
||||
map_ = new_map;
|
||||
}
|
||||
|
||||
void ExtensionSet::InternalReserveSmallCapacityFromEmpty(
|
||||
Arena* arena, size_t minimum_new_capacity) {
|
||||
ABSL_DCHECK(flat_capacity_ == 0);
|
||||
ABSL_DCHECK(IsCompletelyEmpty());
|
||||
ABSL_DCHECK(minimum_new_capacity <= kMaximumFlatCapacity);
|
||||
ABSL_DCHECK(minimum_new_capacity > 0);
|
||||
const size_t new_flat_capacity = absl::bit_ceil(minimum_new_capacity);
|
||||
flat_capacity_ = new_flat_capacity;
|
||||
map_.flat = AllocateFlatMap(arena, new_flat_capacity);
|
||||
set_flat_capacity_and_size(new_flat_capacity, 0);
|
||||
}
|
||||
|
||||
void ExtensionSet::Erase(int key) {
|
||||
if (ABSL_PREDICT_FALSE(is_large())) {
|
||||
map_.large->erase(key);
|
||||
map_.large->large.erase(key);
|
||||
return;
|
||||
}
|
||||
KeyValue* end = flat_end();
|
||||
for (KeyValue* it = flat_begin(); it != end && it->first <= key; ++it) {
|
||||
uint16_t current_cap = flat_capacity();
|
||||
uint16_t current_size = flat_size();
|
||||
FlatItem* end = flat_begin() + current_size;
|
||||
for (FlatItem* it = flat_begin(); it != end && it->first <= key; ++it) {
|
||||
if (it->first == key) {
|
||||
std::copy(it + 1, end, it);
|
||||
--flat_size_;
|
||||
// We need to overwrite capacity in case we overwrote the first element.
|
||||
set_flat_capacity_and_size(current_cap, current_size - 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -580,7 +580,7 @@ class PROTOBUF_EXPORT ExtensionSet {
|
|||
PROTOBUF_FUTURE_ADD_EARLY_NODISCARD uint8_t* _InternalSerialize(
|
||||
const MessageLite* extendee, int start_field_number, int end_field_number,
|
||||
uint8_t* target, io::EpsCopyOutputStream* stream) const {
|
||||
if (flat_size_ == 0) {
|
||||
if (flat_size() == 0) {
|
||||
assert(!is_large());
|
||||
return target;
|
||||
}
|
||||
|
|
@ -592,7 +592,7 @@ class PROTOBUF_EXPORT ExtensionSet {
|
|||
PROTOBUF_FUTURE_ADD_EARLY_NODISCARD uint8_t* _InternalSerializeAll(
|
||||
const MessageLite* extendee, uint8_t* target,
|
||||
io::EpsCopyOutputStream* stream) const {
|
||||
if (flat_size_ == 0) {
|
||||
if (flat_size() == 0) {
|
||||
assert(!is_large());
|
||||
return target;
|
||||
}
|
||||
|
|
@ -891,13 +891,40 @@ class PROTOBUF_EXPORT ExtensionSet {
|
|||
// the number of elements is small enough that linear search is faster than
|
||||
// binary search.
|
||||
|
||||
struct KeyValue {
|
||||
struct FlatItem {
|
||||
int first;
|
||||
// flat_capacity and flat_size are only valid in the first element (index 0)
|
||||
// of flat map array.
|
||||
uint16_t flat_capacity;
|
||||
uint16_t flat_size;
|
||||
Extension second;
|
||||
};
|
||||
|
||||
static void SetFlatCapacityAndSize(FlatItem& item, uint16_t flat_capacity,
|
||||
uint16_t flat_size) {
|
||||
item.flat_capacity = flat_capacity;
|
||||
item.flat_size = flat_size;
|
||||
}
|
||||
|
||||
|
||||
// Constant to represent an empty ExtensionSet.
|
||||
static const FlatItem kEmptyKeyValue;
|
||||
|
||||
using LargeMap = absl::btree_map<int, Extension>;
|
||||
|
||||
struct LargeRep {
|
||||
int unused_padding;
|
||||
uint16_t flat_capacity = ~uint16_t{};
|
||||
uint16_t flat_size = ~uint16_t{};
|
||||
LargeMap large;
|
||||
};
|
||||
|
||||
static_assert(offsetof(FlatItem, flat_capacity) ==
|
||||
offsetof(LargeRep, flat_capacity),
|
||||
"KeyValue and LargeRep layout mismatch");
|
||||
static_assert(offsetof(FlatItem, flat_size) == offsetof(LargeRep, flat_size),
|
||||
"KeyValue and LargeRep layout mismatch");
|
||||
|
||||
// Wrapper API that switches between flat-map and LargeMap.
|
||||
|
||||
// Finds a key (if present) in the ExtensionSet.
|
||||
|
|
@ -927,7 +954,7 @@ class PROTOBUF_EXPORT ExtensionSet {
|
|||
void InternalReserveSmallCapacityFromEmpty(Arena* arena,
|
||||
size_t minimum_new_capacity);
|
||||
|
||||
bool is_large() const { return static_cast<int16_t>(flat_size_) < 0; }
|
||||
bool is_large() const { return static_cast<int16_t>(flat_size()) < 0; }
|
||||
|
||||
// Removes a key from the ExtensionSet.
|
||||
void Erase(int key);
|
||||
|
|
@ -935,7 +962,8 @@ class PROTOBUF_EXPORT ExtensionSet {
|
|||
// Returns the number of elements in the ExtensionSet, including cleared
|
||||
// extensions.
|
||||
size_t Size() const {
|
||||
return ABSL_PREDICT_FALSE(is_large()) ? map_.large->size() : flat_size_;
|
||||
return ABSL_PREDICT_FALSE(is_large()) ? map_.large->large.size()
|
||||
: flat_size();
|
||||
}
|
||||
|
||||
// For use as `PrefetchFunctor`s in `ForEach`.
|
||||
|
|
@ -979,7 +1007,7 @@ class PROTOBUF_EXPORT ExtensionSet {
|
|||
template <typename KeyValueFunctor, typename PrefetchFunctor>
|
||||
void ForEach(KeyValueFunctor func, PrefetchFunctor prefetch_func) {
|
||||
if (ABSL_PREDICT_FALSE(is_large())) {
|
||||
ForEachPrefetchImpl(map_.large->begin(), map_.large->end(),
|
||||
ForEachPrefetchImpl(map_.large->large.begin(), map_.large->large.end(),
|
||||
std::move(func), std::move(prefetch_func));
|
||||
return;
|
||||
}
|
||||
|
|
@ -990,7 +1018,7 @@ class PROTOBUF_EXPORT ExtensionSet {
|
|||
template <typename KeyValueFunctor, typename PrefetchFunctor>
|
||||
void ForEach(KeyValueFunctor func, PrefetchFunctor prefetch_func) const {
|
||||
if (ABSL_PREDICT_FALSE(is_large())) {
|
||||
ForEachPrefetchImpl(map_.large->begin(), map_.large->end(),
|
||||
ForEachPrefetchImpl(map_.large->large.begin(), map_.large->large.end(),
|
||||
std::move(func), std::move(prefetch_func));
|
||||
return;
|
||||
}
|
||||
|
|
@ -1023,7 +1051,7 @@ class PROTOBUF_EXPORT ExtensionSet {
|
|||
template <typename KeyValueFunctor>
|
||||
void ForEachNoPrefetch(KeyValueFunctor func) {
|
||||
if (ABSL_PREDICT_FALSE(is_large())) {
|
||||
ForEachNoPrefetch(map_.large->begin(), map_.large->end(),
|
||||
ForEachNoPrefetch(map_.large->large.begin(), map_.large->large.end(),
|
||||
std::move(func));
|
||||
return;
|
||||
}
|
||||
|
|
@ -1034,7 +1062,7 @@ class PROTOBUF_EXPORT ExtensionSet {
|
|||
template <typename KeyValueFunctor>
|
||||
void ForEachNoPrefetch(KeyValueFunctor func) const {
|
||||
if (ABSL_PREDICT_FALSE(is_large())) {
|
||||
ForEachNoPrefetch(map_.large->begin(), map_.large->end(),
|
||||
ForEachNoPrefetch(map_.large->large.begin(), map_.large->large.end(),
|
||||
std::move(func));
|
||||
return;
|
||||
}
|
||||
|
|
@ -1047,16 +1075,14 @@ class PROTOBUF_EXPORT ExtensionSet {
|
|||
template <typename KeyValueFunctor>
|
||||
bool AnyOfNoPrefetch(KeyValueFunctor predicate) const {
|
||||
if (ABSL_PREDICT_FALSE(is_large())) {
|
||||
return AnyOfNoPrefetch(map_.large->begin(), map_.large->end(),
|
||||
return AnyOfNoPrefetch(map_.large->large.begin(), map_.large->large.end(),
|
||||
std::move(predicate));
|
||||
}
|
||||
return AnyOfNoPrefetch(flat_begin(), flat_end(), std::move(predicate));
|
||||
}
|
||||
|
||||
// Returns true if nothing is allocated in the ExtensionSet.
|
||||
bool IsCompletelyEmpty() const {
|
||||
return flat_size_ == 0 && flat_capacity_ == 0;
|
||||
}
|
||||
bool IsCompletelyEmpty() const { return flat_capacity() == 0; }
|
||||
|
||||
// Reduces the flat_capacity_ to the smallest power of 2 >= flat_size_.
|
||||
void InternalReduceSmallCapacity(Arena* arena);
|
||||
|
|
@ -1223,39 +1249,56 @@ class PROTOBUF_EXPORT ExtensionSet {
|
|||
static inline size_t RepeatedMessage_SpaceUsedExcludingSelfLong(
|
||||
RepeatedPtrFieldBase* field);
|
||||
|
||||
KeyValue* flat_begin() {
|
||||
FlatItem* flat_begin() {
|
||||
assert(!is_large());
|
||||
return map_.flat;
|
||||
}
|
||||
const KeyValue* flat_begin() const {
|
||||
const FlatItem* flat_begin() const {
|
||||
assert(!is_large());
|
||||
return map_.flat;
|
||||
}
|
||||
KeyValue* flat_end() {
|
||||
FlatItem* flat_end() {
|
||||
assert(!is_large());
|
||||
return map_.flat + flat_size_;
|
||||
return map_.flat + flat_size();
|
||||
}
|
||||
const KeyValue* flat_end() const {
|
||||
const FlatItem* flat_end() const {
|
||||
assert(!is_large());
|
||||
return map_.flat + flat_size_;
|
||||
return map_.flat + flat_size();
|
||||
}
|
||||
|
||||
static KeyValue* AllocateFlatMap(Arena* arena,
|
||||
static FlatItem* AllocateFlatMap(Arena* arena,
|
||||
uint16_t powerof2_flat_capacity);
|
||||
static void DeleteFlatMap(const KeyValue* flat, uint16_t flat_capacity);
|
||||
static void DeleteFlatMap(const FlatItem* flat, uint16_t flat_capacity);
|
||||
|
||||
uint16_t flat_capacity() const {
|
||||
ABSL_DCHECK(map_.flat != nullptr);
|
||||
return map_.flat->flat_capacity;
|
||||
}
|
||||
uint16_t flat_size() const {
|
||||
ABSL_DCHECK(map_.flat != nullptr);
|
||||
return map_.flat->flat_size;
|
||||
}
|
||||
void set_flat_capacity_and_size(uint16_t capacity, uint16_t size) {
|
||||
ABSL_DCHECK(map_.flat != &kEmptyKeyValue);
|
||||
SetFlatCapacityAndSize(*map_.flat, capacity, size);
|
||||
}
|
||||
void set_flat_size(uint16_t size) {
|
||||
ABSL_DCHECK(map_.flat != &kEmptyKeyValue);
|
||||
map_.flat->flat_size = size;
|
||||
}
|
||||
|
||||
// Manual memory-management:
|
||||
// map_.flat is an allocated array of flat_capacity_ elements.
|
||||
// [map_.flat, map_.flat + flat_size_) is the currently-in-use prefix.
|
||||
uint16_t flat_capacity_ = 0;
|
||||
uint16_t flat_size_ = 0; // negative int16_t(flat_size_) indicates is_large()
|
||||
// map_.flat is either pointer to kEmptyKeyValue or an allocated array of
|
||||
// flat_capacity elements. [map_.flat, map_.flat + flat_size) is the
|
||||
// currently-in-use prefix.
|
||||
// flat_capacity and flat_size are stored in the first element of the array.
|
||||
union AllocatedData {
|
||||
KeyValue* flat;
|
||||
FlatItem* flat;
|
||||
|
||||
// If flat_capacity_ > kMaximumFlatCapacity, switch to LargeMap,
|
||||
// If flat_capacity > kMaximumFlatCapacity, switch to LargeMap,
|
||||
// which guarantees O(n lg n) CPU but larger constant factors.
|
||||
LargeMap* large;
|
||||
} map_ = {nullptr};
|
||||
LargeRep* large;
|
||||
} map_ = {const_cast<FlatItem*>(&kEmptyKeyValue)};
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
|
|
|||
|
|
@ -371,8 +371,9 @@ int ExtensionSet::SpaceUsedExcludingSelf() const {
|
|||
}
|
||||
|
||||
size_t ExtensionSet::SpaceUsedExcludingSelfLong() const {
|
||||
size_t total_size =
|
||||
(is_large() ? map_.large->size() : flat_capacity_) * sizeof(KeyValue);
|
||||
size_t total_size = is_large() ? map_.large->large.size() * sizeof(FlatItem) +
|
||||
sizeof(LargeRep)
|
||||
: flat_capacity() * sizeof(FlatItem);
|
||||
ForEach(
|
||||
[&total_size](int /* number */, const Extension& ext) {
|
||||
total_size += ext.SpaceUsedExcludingSelfLong();
|
||||
|
|
|
|||
|
|
@ -525,8 +525,8 @@ TEST(ExtensionSetTest, ArenaMergeFromWithClearedExtensions) {
|
|||
}
|
||||
|
||||
TEST(ExtensionSetTest, ArenaMergeFromWithClearedExtensionsReduceCapacity) {
|
||||
if (sizeof(void*) != 8) {
|
||||
GTEST_SKIP() << "This test is only correct on 64-bit systems.";
|
||||
if (!internal::RunLargeMemoryTests()) {
|
||||
GTEST_SKIP() << "Not enough memory for this test.";
|
||||
}
|
||||
Arena arena;
|
||||
auto* message = Arena::Create<unittest::TestAllExtensions>(&arena);
|
||||
|
|
@ -2112,6 +2112,22 @@ TEST(ExtensionSetTest, MessageSetRecursionLimitIsConsistent) {
|
|||
}
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, MergeLargeExtensionSetToEmpty) {
|
||||
ExtensionSet src;
|
||||
ExtensionSet dst;
|
||||
constexpr int kNumExtensions = 70000; // > 2**16 (65536)
|
||||
for (int i = 1; i <= kNumExtensions; ++i) {
|
||||
src.Set<int32_t>(/*arena=*/nullptr, i, WireFormatLite::TYPE_INT32, i,
|
||||
/*descriptor=*/nullptr);
|
||||
}
|
||||
dst.MergeFrom(/*arena=*/nullptr, /*extendee=*/nullptr, src,
|
||||
/*other_arena=*/nullptr);
|
||||
EXPECT_EQ(dst.NumExtensions(), kNumExtensions);
|
||||
for (int i = 1; i <= kNumExtensions; ++i) {
|
||||
EXPECT_EQ(dst.Get<int32_t>(i, 0), i);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
|
|
|||
|
|
@ -845,8 +845,8 @@ TEST(CordInputStreamTest, SkipToEnd) {
|
|||
}
|
||||
|
||||
TEST(CordInputStreamTest, HugeCordNodes) {
|
||||
if (sizeof(void*) < 8) {
|
||||
GTEST_SKIP() << "Not enough memory for test.";
|
||||
if (!internal::RunLargeMemoryTests()) {
|
||||
GTEST_SKIP() << "Not enough memory for this test.";
|
||||
}
|
||||
|
||||
std::string input_str;
|
||||
|
|
|
|||
|
|
@ -1702,8 +1702,8 @@ TEST_P(JsonTest, OversizedStringRejected) {
|
|||
GTEST_SKIP() << "Test is too slow in non-opt builds.";
|
||||
#else
|
||||
|
||||
if (sizeof(void*) < 8) {
|
||||
GTEST_SKIP() << "Test requires 64-bit environment.";
|
||||
if (!internal::RunLargeMemoryTests()) {
|
||||
GTEST_SKIP() << "Not enough memory for this test.";
|
||||
}
|
||||
|
||||
absl::Cord chunk(std::string(1024 * 1024, 'a'));
|
||||
|
|
|
|||
|
|
@ -2731,7 +2731,7 @@ TEST(GeneratedMapFieldTest, SerializationToArray) {
|
|||
}
|
||||
|
||||
TEST(GeneratedMapFieldTest, SerializeLargeString) {
|
||||
if (sizeof(void*) < 8) {
|
||||
if (!internal::RunLargeMemoryTests()) {
|
||||
GTEST_SKIP() << "Not enough memory for this test.";
|
||||
}
|
||||
UNITTEST::TestMap msg;
|
||||
|
|
|
|||
|
|
@ -888,9 +888,8 @@ TEST(MicroStringTest, SetInChunksWontPreallocateForVeryLargeFakeSize) {
|
|||
}
|
||||
|
||||
TEST(MicroStringTest, SetInChunksAllowsVeryLargeValues) {
|
||||
if (sizeof(void*) < 8) {
|
||||
GTEST_SKIP() << "Might not be possible to allocate that much memory on "
|
||||
"this platform.";
|
||||
if (!internal::RunLargeMemoryTests()) {
|
||||
GTEST_SKIP() << "Not enough memory for this test.";
|
||||
}
|
||||
|
||||
std::string total(1'000'000'000, 0);
|
||||
|
|
|
|||
36
src/google/protobuf/offset_ptr.cc
Normal file
36
src/google/protobuf/offset_ptr.cc
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include "google/protobuf/offset_ptr.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "absl/log/absl_log.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
void BasePointerInvalidSelfReference() noexcept {
|
||||
ABSL_LOG(FATAL) << "Nullable base pointer can't self reference.";
|
||||
}
|
||||
|
||||
void BasePointerNonnullFailure() noexcept {
|
||||
ABSL_LOG(FATAL)
|
||||
<< "Non-nullable base pointer constructed with a null pointer.";
|
||||
}
|
||||
|
||||
void BasePointerOverflow(const void* ptr, const void* base) noexcept {
|
||||
ptrdiff_t diff =
|
||||
reinterpret_cast<const char*>(ptr) - reinterpret_cast<const char*>(base);
|
||||
ABSL_LOG(FATAL) << "Pointer out of scope for offset pointer: ptr=" << ptr
|
||||
<< " base=" << base << " diff=" << diff;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
177
src/google/protobuf/offset_ptr.h
Normal file
177
src/google/protobuf/offset_ptr.h
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_OFFSET_PTR_H__
|
||||
#define GOOGLE_PROTOBUF_OFFSET_PTR_H__
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/base/optimization.h"
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
[[noreturn]] PROTOBUF_PRESERVE_ALL PROTOBUF_EXPORT void BasePointerOverflow(
|
||||
const void* ptr, const void* base) noexcept;
|
||||
[[noreturn]] PROTOBUF_PRESERVE_ALL PROTOBUF_EXPORT void
|
||||
BasePointerInvalidSelfReference() noexcept;
|
||||
[[noreturn]] PROTOBUF_PRESERVE_ALL PROTOBUF_EXPORT void
|
||||
BasePointerNonnullFailure() noexcept;
|
||||
|
||||
// Offset based pointer-like class.
|
||||
// It encodes its data relative to a `base` pointer.
|
||||
// The caller must provide this pointer and it must be the same base pointer
|
||||
// pass to `Resolve`.
|
||||
// The offset is encoded in 32-bit and the caller must guarantee that.
|
||||
//
|
||||
// Is kAllowNull is false, then nullptr is not a valid input and will terminate
|
||||
// the program. However, such mode is faster. The caller should choose the
|
||||
// appropriate setting for the pointer in question.
|
||||
template <typename T, bool kAllowNull>
|
||||
class BasePointer {
|
||||
// We must use 0 as the null pointer because some of these are initialized via
|
||||
// memset.
|
||||
static constexpr int32_t kNullOffset = 0;
|
||||
|
||||
public:
|
||||
// Uninitialized.
|
||||
BasePointer() = default;
|
||||
|
||||
// Trivial copy/assign.
|
||||
BasePointer(const BasePointer&) = default;
|
||||
BasePointer& operator=(const BasePointer&) = default;
|
||||
|
||||
BasePointer(T* ptr, const void* base) {
|
||||
if constexpr (kAllowNull) {
|
||||
if (ptr == nullptr) {
|
||||
offset_ = kNullOffset;
|
||||
return;
|
||||
}
|
||||
if (ABSL_PREDICT_FALSE(ptr == base)) {
|
||||
BasePointerInvalidSelfReference();
|
||||
}
|
||||
} else {
|
||||
if (ABSL_PREDICT_FALSE(ptr == nullptr)) {
|
||||
BasePointerNonnullFailure();
|
||||
}
|
||||
}
|
||||
|
||||
ptrdiff_t diff = reinterpret_cast<const char*>(ptr) -
|
||||
reinterpret_cast<const char*>(base);
|
||||
if (ABSL_PREDICT_FALSE(static_cast<int32_t>(diff) != diff)) {
|
||||
BasePointerOverflow(ptr, base);
|
||||
}
|
||||
|
||||
offset_ = static_cast<int32_t>(diff);
|
||||
}
|
||||
|
||||
// `base` must be the same `base` pointer as the one passed to the
|
||||
// constructor.
|
||||
T* Resolve(const void* base) const {
|
||||
if constexpr (kAllowNull) {
|
||||
if (offset_ == kNullOffset) return nullptr;
|
||||
}
|
||||
T* out = const_cast<T*>(reinterpret_cast<const T*>(
|
||||
reinterpret_cast<const char*>(base) + offset_));
|
||||
PROTOBUF_ASSUME(out != nullptr);
|
||||
return out;
|
||||
}
|
||||
|
||||
private:
|
||||
int32_t offset_;
|
||||
};
|
||||
|
||||
// Offset based pointer class.
|
||||
// It uses its own address as the base pointer, which simplifies its use but
|
||||
// restricts the input pointer to be in the same slab of memory as the
|
||||
// `OffsetPtr` instance itself.
|
||||
// kAllowNull follows the semantics of BasePointer.
|
||||
template <typename T, bool kAllowNull>
|
||||
class OffsetPtr {
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
OffsetPtr() = default;
|
||||
|
||||
// Bit copy is wrong because we are relative to `this`.
|
||||
OffsetPtr(const OffsetPtr&) = delete;
|
||||
OffsetPtr& operator=(const OffsetPtr&) = delete;
|
||||
|
||||
// We can't have a conversion constructor because it would allow for
|
||||
// temporaries to be made, which breaks the invariant of maximum distance.
|
||||
|
||||
T* get() const { return ptr_.Resolve(this); }
|
||||
operator T*() const { return get(); } // NOLINT
|
||||
T* operator->() const { return get(); }
|
||||
|
||||
OffsetPtr& operator=(T* value) {
|
||||
ptr_ = BasePointer<T, kAllowNull>(value, this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
OffsetPtr& operator=(std::nullptr_t) {
|
||||
static_assert(kAllowNull, "Can't accept null.");
|
||||
return *this = static_cast<T*>(nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
BasePointer<T, kAllowNull> ptr_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using NullableOffsetPtr = OffsetPtr<T, true>;
|
||||
|
||||
template <typename T>
|
||||
using NonnullOffsetPtr = OffsetPtr<T, false>;
|
||||
|
||||
// Same as OffsetPtr, with a special case &T::default_instance.
|
||||
// The pointer can be set to `&T::default_instance()` even though it is outside
|
||||
// the range. It is handled specially.
|
||||
// Null inputs are equivalent to the default instance.
|
||||
template <typename T>
|
||||
class OffsetProtoPtr {
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
OffsetProtoPtr() = default;
|
||||
|
||||
// Bit copy is wrong because we are relative to `this`.
|
||||
OffsetProtoPtr(const OffsetProtoPtr&) = delete;
|
||||
OffsetProtoPtr& operator=(const OffsetProtoPtr&) = delete;
|
||||
|
||||
// We can't have a conversion constructor because it would allow for
|
||||
// temporaries to be made, which breaks the invariant of maximum distance.
|
||||
|
||||
T* get() const {
|
||||
T* value = ptr_.Resolve(this);
|
||||
return value == nullptr ? &T::default_instance() : value;
|
||||
}
|
||||
operator T*() const { return get(); } // NOLINT
|
||||
T* operator->() const { return get(); }
|
||||
|
||||
OffsetProtoPtr& operator=(T* value) {
|
||||
ptr_ = BasePointer<T, true>(
|
||||
value == &T::default_instance() ? nullptr : value, this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
BasePointer<T, true> ptr_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#include "google/protobuf/port_undef.inc"
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_OFFSET_PTR_H__
|
||||
132
src/google/protobuf/offset_ptr_test.cc
Normal file
132
src/google/protobuf/offset_ptr_test.cc
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include "google/protobuf/offset_ptr.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "google/protobuf/unittest.pb.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
||||
int array[10];
|
||||
|
||||
TEST(BasePtrTest, Basic) {
|
||||
BasePointer<int, false> b(&array[5], &array);
|
||||
EXPECT_EQ(&array[5], b.Resolve(&array));
|
||||
}
|
||||
|
||||
TEST(BasePtrTest, Copyable) {
|
||||
EXPECT_TRUE(
|
||||
(std::is_trivially_copy_constructible_v<BasePointer<int, false>>));
|
||||
EXPECT_TRUE((std::is_trivially_copy_assignable_v<BasePointer<int, false>>));
|
||||
EXPECT_TRUE((std::is_trivially_destructible_v<BasePointer<int, false>>));
|
||||
|
||||
BasePointer<int, false> b(&array[7], &array);
|
||||
EXPECT_EQ(&array[7], b.Resolve(&array));
|
||||
|
||||
auto b2 = b;
|
||||
EXPECT_EQ(&array[7], b2.Resolve(&array));
|
||||
}
|
||||
|
||||
TEST(BasePtrTest, BaseCanBeOnEitherSide) {
|
||||
EXPECT_EQ(&array[7],
|
||||
(BasePointer<int, false>(&array[7], &array[3])).Resolve(&array[3]));
|
||||
EXPECT_EQ(&array[4],
|
||||
(BasePointer<int, false>(&array[4], &array[7])).Resolve(&array[7]));
|
||||
}
|
||||
|
||||
TEST(BasePtrTest, BaseCanBeSameAsPointer) {
|
||||
int var = 0;
|
||||
|
||||
EXPECT_EQ(&var, (BasePointer<int, false>(&var, &var)).Resolve(&var));
|
||||
}
|
||||
|
||||
TEST(BasePtrTest, NullIsAllowed) {
|
||||
bool dummy = false;
|
||||
BasePointer<int, true> b(nullptr, &dummy);
|
||||
EXPECT_EQ(nullptr, b.Resolve(&dummy));
|
||||
|
||||
int p = 0;
|
||||
EXPECT_DEATH((BasePointer<int, true>(&p, &p)),
|
||||
"Nullable base pointer can't self reference");
|
||||
|
||||
EXPECT_DEATH((BasePointer<int, false>(nullptr, &dummy)),
|
||||
"Non-nullable base pointer constructed with a null pointer");
|
||||
}
|
||||
|
||||
TEST(BasePtrTest, OutOfScopeFails) {
|
||||
// For this one we manufacture pointers to make sure they trigger out of scope
|
||||
// failures.
|
||||
if (sizeof(void*) == 4) {
|
||||
GTEST_SKIP() << "We need 64-bit to have out-of-scope pointers.";
|
||||
}
|
||||
|
||||
void* base =
|
||||
reinterpret_cast<void*>(static_cast<uintptr_t>(0x123457890abcdef));
|
||||
|
||||
const auto make_ptr = [&](ptrdiff_t diff) {
|
||||
return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(base) + diff);
|
||||
};
|
||||
|
||||
using T = BasePointer<void, false>;
|
||||
|
||||
// INT_MAX is fine.
|
||||
EXPECT_EQ(T(make_ptr(std::numeric_limits<int>::max()), base).Resolve(base),
|
||||
make_ptr(std::numeric_limits<int>::max()));
|
||||
|
||||
// INT_MAX+1 is too much.
|
||||
EXPECT_DEATH(
|
||||
T(make_ptr(ptrdiff_t{std::numeric_limits<int>::max()} + 1), base),
|
||||
"Pointer out of scope for offset pointer");
|
||||
|
||||
// INT_MIN is fine.
|
||||
EXPECT_EQ(T(make_ptr(std::numeric_limits<int>::min()), base).Resolve(base),
|
||||
make_ptr(std::numeric_limits<int>::min()));
|
||||
|
||||
// INT_MIN-1 is too much.
|
||||
EXPECT_DEATH(
|
||||
T(make_ptr(ptrdiff_t{std::numeric_limits<int>::min()} - 1), base),
|
||||
"Pointer out of scope for offset pointer");
|
||||
}
|
||||
|
||||
TEST(OffsetPtrTest, Basic) {
|
||||
struct Object {
|
||||
int array[10];
|
||||
OffsetPtr<int, false> ptr;
|
||||
} object{};
|
||||
|
||||
object.ptr = object.array + 3;
|
||||
EXPECT_EQ(object.ptr, object.array + 3);
|
||||
}
|
||||
|
||||
TEST(OffsetProtoPtr, Basic) {
|
||||
using P = proto2_unittest::TestAllTypes;
|
||||
OffsetProtoPtr<const P> p;
|
||||
|
||||
p = nullptr;
|
||||
EXPECT_EQ(&P::default_instance(), p);
|
||||
|
||||
P msg;
|
||||
p = &msg;
|
||||
EXPECT_EQ(&msg, p);
|
||||
|
||||
p = &P::default_instance();
|
||||
EXPECT_EQ(&P::default_instance(), p);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
|
@ -500,34 +500,7 @@ void OptionInterpreter::UpdateSourceCodeInfo(SourceCodeInfo* info) {
|
|||
}
|
||||
|
||||
if (loc_matches) {
|
||||
if (loc->path_size() == static_cast<int64_t>(match_src.size() + 1)) {
|
||||
int uninterpreted_field = loc->path(match_src.size());
|
||||
|
||||
SourceCodeInfo_Location* mapped_loc = new_locs.Add();
|
||||
*mapped_loc = *loc;
|
||||
mapped_loc->mutable_path()->Assign(match_dest.begin(),
|
||||
match_dest.end());
|
||||
mapped_loc->add_path(uninterpreted_field);
|
||||
|
||||
if (uninterpreted_field ==
|
||||
UninterpretedOption::kAggregateValueFieldNumber) {
|
||||
auto it = agg_loc_map.find(loc->path());
|
||||
if (it != agg_loc_map.end()) {
|
||||
for (const AggregateFieldLocation* afl : it->second) {
|
||||
SourceCodeInfo_Location* name_loc = new_locs.Add();
|
||||
name_loc->mutable_path()->Assign(afl->field_dest_path.begin(),
|
||||
afl->field_dest_path.end());
|
||||
name_loc->add_path(UninterpretedOption::kNameFieldNumber);
|
||||
SetSpan(name_loc, *loc, afl->name_range);
|
||||
SourceCodeInfo_Location* val_loc = new_locs.Add();
|
||||
val_loc->mutable_path()->Assign(afl->field_dest_path.begin(),
|
||||
afl->field_dest_path.end());
|
||||
val_loc->add_path(afl->value_marker);
|
||||
SetSpan(val_loc, *loc, afl->val_range);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: b/168903973 - Remove once we update the format.
|
||||
// don't copy this row since it is a sub-location that we're removing
|
||||
// (or we already mapped it if it's a direct child)
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -320,6 +320,14 @@ constexpr bool HasAnySanitizer() {
|
|||
#endif
|
||||
}
|
||||
|
||||
constexpr bool RunLargeMemoryTests() {
|
||||
// For tests that need a lot of memory, we check that we have a 64-bit
|
||||
// platform.
|
||||
// And we also check we are not using sanitizers. They increase memory
|
||||
// requirements and can be too slow for those tests.
|
||||
return sizeof(void*) == 8 && !HasAnySanitizer();
|
||||
}
|
||||
|
||||
constexpr bool PerformDebugChecks() {
|
||||
if (HasAnySanitizer()) return true;
|
||||
#if defined(NDEBUG)
|
||||
|
|
|
|||
|
|
@ -169,8 +169,8 @@ TEST(RepeatedField, Small) {
|
|||
class RepeatedFieldIsFullTest : public testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
if (sizeof(void*) == 4) {
|
||||
GTEST_SKIP() << "Platform does not have enough memory for the test.";
|
||||
if (!internal::RunLargeMemoryTests()) {
|
||||
GTEST_SKIP() << "Not enough memory for this test.";
|
||||
}
|
||||
if (internal::GetBoundsCheckMode() != internal::BoundsCheckMode::kAbort) {
|
||||
GTEST_SKIP() << "Preemtive abort is not enabled.";
|
||||
|
|
|
|||
|
|
@ -233,11 +233,12 @@ TEST(RetentionTest, StripSourceRetentionOptionsWithSourceCodeInfo) {
|
|||
compiler::StripSourceRetentionOptions(*interpreted_desc,
|
||||
/*include_source_code_info=*/true);
|
||||
|
||||
EXPECT_EQ(interpreted_unstripped_file.source_code_info().location_size(), 92);
|
||||
// TODO: b/168903973 - Remove once we update the format.
|
||||
EXPECT_EQ(interpreted_unstripped_file.source_code_info().location_size(), 64);
|
||||
|
||||
// Stripping removes source-retention options (including some sub-fields),
|
||||
// reducing the location count.
|
||||
EXPECT_EQ(stripped_file.source_code_info().location_size(), 89);
|
||||
EXPECT_EQ(stripped_file.source_code_info().location_size(), 63);
|
||||
}
|
||||
|
||||
TEST(RetentionTest, RemoveEmptyOptions) {
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ upb_amalgamation(
|
|||
"//upb/text:debug",
|
||||
"//upb/text:internal",
|
||||
"//upb/wire",
|
||||
"//upb/wire:encode_extension",
|
||||
"//upb/wire:back_alloc",
|
||||
"//upb/wire:byte_size",
|
||||
"//upb/wire:decoder",
|
||||
|
|
@ -248,6 +249,7 @@ upb_amalgamation(
|
|||
"//upb/reflection:json_enumvalue_options_upb_proto",
|
||||
"//upb/reflection:internal",
|
||||
"//upb/wire",
|
||||
"//upb/wire:encode_extension",
|
||||
"//upb/wire:back_alloc",
|
||||
"//upb/wire:decoder",
|
||||
"//upb/wire:encoder",
|
||||
|
|
@ -307,6 +309,7 @@ upb_amalgamation(
|
|||
"//upb/reflection:internal",
|
||||
"//upb/util:def_to_proto",
|
||||
"//upb/wire",
|
||||
"//upb/wire:encode_extension",
|
||||
"//upb/wire:back_alloc",
|
||||
"//upb/wire:decoder",
|
||||
"//upb/wire:encoder",
|
||||
|
|
|
|||
|
|
@ -73,6 +73,9 @@ static upb_Arena* jsonenc_arena(jsonenc* e) {
|
|||
/* Create lazily, since it's only needed for Any */
|
||||
if (!e->arena) {
|
||||
e->arena = upb_Arena_New();
|
||||
if (!e->arena) {
|
||||
jsonenc_err(e, "Out of memory");
|
||||
}
|
||||
}
|
||||
return e->arena;
|
||||
}
|
||||
|
|
@ -390,6 +393,10 @@ static void jsonenc_any(jsonenc* e, const upb_Message* msg,
|
|||
const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m);
|
||||
upb_Arena* arena = jsonenc_arena(e);
|
||||
upb_Message* any = upb_Message_New(any_layout, arena);
|
||||
if (!any) {
|
||||
jsonenc_err(e, "Out of memory");
|
||||
return;
|
||||
}
|
||||
|
||||
if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) !=
|
||||
kUpb_DecodeStatus_Ok) {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "upb/json/encode.h"
|
||||
#include "upb/json/test.upb.h"
|
||||
#include "upb/json/test.upbdefs.h"
|
||||
#include "upb/mem/alloc.h"
|
||||
#include "upb/mem/arena.h"
|
||||
#include "upb/mem/arena.hpp"
|
||||
#include "upb/reflection/def.hpp"
|
||||
|
|
@ -50,6 +51,68 @@ void DecodeEncodeArbitraryJson(std::string_view json) {
|
|||
size_t written = upb_JsonEncode(UPB_UPCAST(box), m.ptr(), defpool.ptr(),
|
||||
options, json_buf, size + 1, status.ptr());
|
||||
EXPECT_EQ(written, size);
|
||||
|
||||
if (upb_AllocationCount_IsAvailable()) {
|
||||
auto RunJsonScenario = [&]() -> bool {
|
||||
upb_Arena* local_arena = upb_Arena_New();
|
||||
if (!local_arena) return false;
|
||||
|
||||
upb_test_Box* local_box = upb_test_Box_new(local_arena);
|
||||
if (!local_box) {
|
||||
upb_Arena_Free(local_arena);
|
||||
return false;
|
||||
}
|
||||
|
||||
upb::Status local_status;
|
||||
bool local_ok = upb_JsonDecode(
|
||||
json.data(), json.size(), UPB_UPCAST(local_box), m.ptr(),
|
||||
defpool.ptr(), options, local_arena, local_status.ptr());
|
||||
if (!local_ok) {
|
||||
upb_Arena_Free(local_arena);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t local_sz =
|
||||
upb_JsonEncode(UPB_UPCAST(local_box), m.ptr(), defpool.ptr(), options,
|
||||
nullptr, 0, local_status.ptr());
|
||||
if (local_sz == (size_t)-1 || !local_status.ok()) {
|
||||
upb_Arena_Free(local_arena);
|
||||
return false;
|
||||
}
|
||||
|
||||
char* local_json_buf = (char*)upb_Arena_Malloc(local_arena, local_sz + 1);
|
||||
if (!local_json_buf) {
|
||||
upb_Arena_Free(local_arena);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t local_written =
|
||||
upb_JsonEncode(UPB_UPCAST(local_box), m.ptr(), defpool.ptr(), options,
|
||||
local_json_buf, local_sz + 1, local_status.ptr());
|
||||
if (local_written == (size_t)-1 || !local_status.ok()) {
|
||||
upb_Arena_Free(local_arena);
|
||||
return false;
|
||||
}
|
||||
|
||||
upb_Arena_Free(local_arena);
|
||||
return true;
|
||||
};
|
||||
|
||||
upb_AllocationCount_Reset();
|
||||
if (RunJsonScenario()) {
|
||||
size_t total_allocations = upb_AllocationCount_Get();
|
||||
for (size_t i = 0; i < total_allocations; ++i) {
|
||||
upb_AllocationCount_Reset();
|
||||
upb_AllocationCount_FailOn(i);
|
||||
bool success_with_fail = RunJsonScenario();
|
||||
EXPECT_FALSE(success_with_fail)
|
||||
<< "Fuzzed JSON scenario unexpectedly succeeded when allocation "
|
||||
<< "number " << i << " was failed, with "
|
||||
<< upb_AllocationCount_Get() << " total.";
|
||||
}
|
||||
}
|
||||
upb_AllocationCount_Reset();
|
||||
}
|
||||
}
|
||||
FUZZ_TEST(FuzzTest, DecodeEncodeArbitraryJson);
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ cc_library(
|
|||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":internal",
|
||||
":message_unknowns",
|
||||
":types",
|
||||
"//upb/base",
|
||||
"//upb/base:internal",
|
||||
|
|
@ -70,6 +69,7 @@ cc_library(
|
|||
features = UPB_DEFAULT_FEATURES,
|
||||
visibility = [
|
||||
"//hpb/internal:__pkg__",
|
||||
"//multiplatform/elements/engine/imports/eml_operators:__pkg__",
|
||||
"//pkg:__pkg__",
|
||||
"//python:__pkg__",
|
||||
"//third_party/cel/c/internal:__pkg__",
|
||||
|
|
@ -527,6 +527,8 @@ cc_test(
|
|||
deps = [
|
||||
":internal",
|
||||
":message",
|
||||
":message_test_upb_minitable_proto",
|
||||
":message_test_upb_proto",
|
||||
":message_unknowns",
|
||||
"//upb/base",
|
||||
"//upb/mem",
|
||||
|
|
@ -535,6 +537,7 @@ cc_test(
|
|||
"//upb/test:test_proto_upb_minitable",
|
||||
"//upb/test:test_upb_proto",
|
||||
"//upb/wire",
|
||||
"//upb/wire:encode_extension",
|
||||
"@googletest//:gtest",
|
||||
"@googletest//:gtest_main",
|
||||
],
|
||||
|
|
|
|||
|
|
@ -42,12 +42,21 @@ upb_Extension* UPB_PRIVATE(_upb_Message_GetOrCreateExtensionWithTag)(
|
|||
struct upb_Message* msg, const upb_MiniTableExtension* e, upb_Arena* a,
|
||||
upb_TaggedAuxType tag) {
|
||||
UPB_ASSERT(!upb_Message_IsFrozen(msg));
|
||||
upb_Extension* ext = (upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e);
|
||||
if (ext) return ext;
|
||||
|
||||
// For Canonical Extensions, we check whether the extension has already been
|
||||
// set. If we find an extension with the same pointer and tag, we reuse it to
|
||||
// prevent duplicate entries for the same extension.
|
||||
//
|
||||
// For Non-Canonical Extensions, we do NOT reuse them, matching the behavior
|
||||
// of adding a unknown StringView (through `_upb_Message_AddUnknown`) which
|
||||
// accumulates.
|
||||
if (tag == kUpb_TaggedAuxType_CanonicalExtension) {
|
||||
upb_Extension* ext =
|
||||
(upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e);
|
||||
if (ext) return ext;
|
||||
}
|
||||
if (!UPB_PRIVATE(_upb_Message_ReserveSlot)(msg, a)) return NULL;
|
||||
upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
|
||||
ext = upb_Arena_Malloc(a, sizeof(upb_Extension));
|
||||
upb_Extension* ext = upb_Arena_Malloc(a, sizeof(upb_Extension));
|
||||
if (!ext) return NULL;
|
||||
memset(ext, 0, sizeof(upb_Extension));
|
||||
ext->ext = e;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue