1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 15:23:05 +04:00

Compare commits

..

14 Commits

Author SHA1 Message Date
Ruslan Garnov 6860e8ed77 Added desync RMats and MediaFrames support 2021-10-12 11:54:22 +03:00
Maxim Pashchenkov 719059f671 G-API: Removing ParseSSD overload.
* Removed specialization.

* Removed united

original commit: 651967b95c
2021-10-12 11:54:22 +03:00
Anatoliy Talamanov 4eb82c2ed0 G-API: Handle reshape for generic case in GExecutor
* Handle reshape for generic case for GExecutor

* Add initResources

* Add tests

* Refactor reshape method

original commit: 499d8adb75
2021-10-12 11:54:22 +03:00
Anatoliy Talamanov 5516c2eda1 Fix GExecutor WriteBackExec 2021-10-12 11:54:22 +03:00
Anatoliy Talamanov 18ea4758e2 Check adapter in executor 2021-10-12 11:54:22 +03:00
Anatoliy Talamanov 1c2792bc60 [G-API] Extend compileStreaming to support different overloads
* Make different overloads

* Order python compileStreaming overloads

* Fix compileStreaming bug

* Replace

gin -> descr_of

* Set error message

* Fix review comments

* Use macros for pyopencv_to GMetaArgs
* Use GAPI_PROP_RW
* Not split Prims python stuff

original commit: 5ad6ff239b
2021-10-12 11:54:22 +03:00
Maxim Pashchenkov eb68476aaf G-API: Python. Desync.
* Desync. GMat.

* Alignment

original commit: 05f1939b02
2021-10-12 11:54:22 +03:00
Anatoliy Talamanov 8d0fc8bfb5 G-API: Wrap render functionality to python
* Wrap render Rect prim

* Add all primitives and tests

* Cover mosaic and image

* Handle error in pyopencv_to(Prim)

* Move Mosaic and Rect ctors wrappers to shadow file

* Use GAPI_PROP_RW

* Fix indent

original commit: 9fe49497bb
2021-10-12 11:54:22 +03:00
Anatoliy Talamanov e2f5671280 G-API: Extend python bindings
* Extend G-API bindings

* Wrap timestamp, seqNo, seq_id
* Wrap copy
* Wrap parseSSD, parseYolo

* Rewrap cv.gapi.networks

* Add test for metabackend in pytnon

* Remove int64 pyopencv_to

original commit: fb7ef76e74
2021-10-12 11:54:11 +03:00
Anatoliy Talamanov ba30403581 G-API: Support vaargs for cv.compile_args
* Support cv.compile_args to work with variadic number of inputs

* Disable python2.x G-API

* Move compile_args to gapi pkg

original commit: 53eca2ff5b
2021-10-12 11:44:19 +03:00
Anatoliy Talamanov 0a31fa19f8 [G-API] Expand PyParams to support constInput
* Wrap constInputs to python

* Wrap cfgNumRequests

* Fix alignment

* Move macro to the line above

original commit: ba539eb9aa
2021-10-12 11:43:53 +03:00
Maksim Shabunin 8cfe9546f3 Option to enable/disable plugin linking with OpenCV 2021-08-16 15:01:29 +03:00
Vincent Rabaud fd2b5411e4 Fix potential NaN in cv::norm.
There can be an int overflow.
cv::norm( InputArray _src, int normType, InputArray _mask ) is fine,
not cv::norm( InputArray _src1, InputArray _src2, int normType, InputArray _mask ).
2021-06-15 21:21:21 +03:00
Alexander Alekhin dd66cccbbd OpenCV version '-openvino' 2021-06-10 16:51:21 +03:00
1514 changed files with 171780 additions and 232806 deletions
+7 -7
View File
@@ -34,11 +34,11 @@ This is a template helping you to create an issue which can be processed as quic
- [ ] I report the issue, it's not a question
<!--
OpenCV team works with forum.opencv.org, Stack Overflow and other communities
to discuss problems. Tickets with questions without a real issue statement will be
to discuss problems. Tickets with question without real issue statement will be
closed.
-->
- [ ] I checked the problem with documentation, FAQ, open issues,
forum.opencv.org, Stack Overflow, etc and have not found any solution
forum.opencv.org, Stack Overflow, etc and have not found solution
<!--
Places to check:
* OpenCV documentation: https://docs.opencv.org
@@ -47,11 +47,11 @@ This is a template helping you to create an issue which can be processed as quic
* OpenCV issue tracker: https://github.com/opencv/opencv/issues?q=is%3Aissue
* Stack Overflow branch: https://stackoverflow.com/questions/tagged/opencv
-->
- [ ] I updated to the latest OpenCV version and the issue is still there
- [ ] I updated to latest OpenCV version and the issue is still there
<!--
master branch for OpenCV 4.x and 3.4 branch for OpenCV 3.x releases.
OpenCV team supports only the latest release for each branch.
The ticket is closed if the problem is not reproduced with the modern version.
OpenCV team supports only latest release for each branch.
The ticket is closed, if the problem is not reproduced with modern version.
-->
- [ ] There is reproducer code and related data files: videos, images, onnx, etc
<!--
@@ -61,9 +61,9 @@ This is a template helping you to create an issue which can be processed as quic
to reduce attachment size
* Use PNG for images, if you report some CV related bug, but not image reader
issue
* Attach the image as an archive to the ticket, if you report some reader issue.
* Attach the image as archive to the ticket, if you report some reader issue.
Image hosting services compress images and it breaks the repro code.
* Provide ONNX file for some public model or ONNX file with random weights,
* Provide ONNX file for some public model or ONNX file with with random weights,
if you report ONNX parsing or handling issue. Architecture details diagram
from netron tool can be very useful too. See https://lutzroeder.github.io/netron/
-->
+3 -3
View File
@@ -3,9 +3,9 @@
See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request
- [ ] I agree to contribute to the project under Apache 2 License.
- [ ] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [ ] The PR is proposed to the proper branch
- [ ] There is a reference to the original bug report and related work
- [ ] To the best of my knowledge, the proposed patch is not based on a code under GPL or other license that is incompatible with OpenCV
- [ ] The PR is proposed to proper branch
- [ ] There is reference to original bug report and related work
- [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
Patch to opencv_extra has the same branch name.
- [ ] The feature is well documented and sample code can be built with the project CMake
-19
View File
@@ -1,19 +0,0 @@
name: PR:4.x
on:
pull_request:
branches:
- 4.x
jobs:
ARM64:
uses: opencv/ci-gha-workflow/.github/workflows/OCV-PR-4.x-ARM64.yaml@main
U20:
uses: opencv/ci-gha-workflow/.github/workflows/OCV-PR-4.x-U20.yaml@main
W10:
uses: opencv/ci-gha-workflow/.github/workflows/OCV-PR-4.x-W10.yaml@main
TIM-VX:
uses: opencv/ci-gha-workflow/.github/workflows/OCV-timvx-backend-tests-4.x.yml@main
-25
View File
@@ -1,25 +0,0 @@
name: lint_python
on: workflow_dispatch
jobs:
lint_python:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- run: pip install --upgrade pip wheel
- run: pip install bandit black codespell flake8 flake8-2020 flake8-bugbear
flake8-comprehensions isort mypy pytest pyupgrade safety
- run: bandit --recursive --skip B101 . || true # B101 is assert statements
- run: black --check . || true
- run: codespell || true # --ignore-words-list="" --skip="*.css,*.js,*.lock"
- run: flake8 . --count --select=E9,F63,F7 --show-source --statistics
- run: flake8 . --count --exit-zero --max-complexity=10 --max-line-length=88
--show-source --statistics
- run: isort --check-only --profile black . || true
- run: pip install -r requirements.txt || pip install --editable . || true
- run: mkdir --parents --verbose .mypy_cache
- run: mypy --ignore-missing-imports --install-types --non-interactive . || true
- run: pytest . || true
- run: pytest --doctest-modules . || true
- run: shopt -s globstar && pyupgrade --py36-plus **/*.py || true
- run: safety check
+17 -26
View File
@@ -1778,30 +1778,30 @@ TegraCvtColor_Invoker(bgrx2hsvf, bgrx2hsv, src_data + static_cast<size_t>(range.
: CV_HAL_ERROR_NOT_IMPLEMENTED \
)
#define TEGRA_CVT2PYUVTOBGR_EX(y_data, y_step, uv_data, uv_step, dst_data, dst_step, dst_width, dst_height, dcn, swapBlue, uIdx) \
#define TEGRA_CVT2PYUVTOBGR(src_data, src_step, dst_data, dst_step, dst_width, dst_height, dcn, swapBlue, uIdx) \
( \
CAROTENE_NS::isSupportedConfiguration() ? \
dcn == 3 ? \
uIdx == 0 ? \
(swapBlue ? \
CAROTENE_NS::yuv420i2rgb(CAROTENE_NS::Size2D(dst_width, dst_height), \
y_data, y_step, \
uv_data, uv_step, \
src_data, src_step, \
src_data + src_step * dst_height, src_step, \
dst_data, dst_step) : \
CAROTENE_NS::yuv420i2bgr(CAROTENE_NS::Size2D(dst_width, dst_height), \
y_data, y_step, \
uv_data, uv_step, \
src_data, src_step, \
src_data + src_step * dst_height, src_step, \
dst_data, dst_step)), \
CV_HAL_ERROR_OK : \
uIdx == 1 ? \
(swapBlue ? \
CAROTENE_NS::yuv420sp2rgb(CAROTENE_NS::Size2D(dst_width, dst_height), \
y_data, y_step, \
uv_data, uv_step, \
src_data, src_step, \
src_data + src_step * dst_height, src_step, \
dst_data, dst_step) : \
CAROTENE_NS::yuv420sp2bgr(CAROTENE_NS::Size2D(dst_width, dst_height), \
y_data, y_step, \
uv_data, uv_step, \
src_data, src_step, \
src_data + src_step * dst_height, src_step, \
dst_data, dst_step)), \
CV_HAL_ERROR_OK : \
CV_HAL_ERROR_NOT_IMPLEMENTED : \
@@ -1809,32 +1809,29 @@ TegraCvtColor_Invoker(bgrx2hsvf, bgrx2hsv, src_data + static_cast<size_t>(range.
uIdx == 0 ? \
(swapBlue ? \
CAROTENE_NS::yuv420i2rgbx(CAROTENE_NS::Size2D(dst_width, dst_height), \
y_data, y_step, \
uv_data, uv_step, \
src_data, src_step, \
src_data + src_step * dst_height, src_step, \
dst_data, dst_step) : \
CAROTENE_NS::yuv420i2bgrx(CAROTENE_NS::Size2D(dst_width, dst_height), \
y_data, y_step, \
uv_data, uv_step, \
src_data, src_step, \
src_data + src_step * dst_height, src_step, \
dst_data, dst_step)), \
CV_HAL_ERROR_OK : \
uIdx == 1 ? \
(swapBlue ? \
CAROTENE_NS::yuv420sp2rgbx(CAROTENE_NS::Size2D(dst_width, dst_height), \
y_data, y_step, \
uv_data, uv_step, \
src_data, src_step, \
src_data + src_step * dst_height, src_step, \
dst_data, dst_step) : \
CAROTENE_NS::yuv420sp2bgrx(CAROTENE_NS::Size2D(dst_width, dst_height), \
y_data, y_step, \
uv_data, uv_step, \
src_data, src_step, \
src_data + src_step * dst_height, src_step, \
dst_data, dst_step)), \
CV_HAL_ERROR_OK : \
CV_HAL_ERROR_NOT_IMPLEMENTED : \
CV_HAL_ERROR_NOT_IMPLEMENTED \
: CV_HAL_ERROR_NOT_IMPLEMENTED \
)
#define TEGRA_CVT2PYUVTOBGR(src_data, src_step, dst_data, dst_step, dst_width, dst_height, dcn, swapBlue, uIdx) \
TEGRA_CVT2PYUVTOBGR_EX(src_data, src_step, src_data + src_step * dst_height, src_step, dst_data, dst_step, \
dst_width, dst_height, dcn, swapBlue, uIdx);
#undef cv_hal_cvtBGRtoBGR
#define cv_hal_cvtBGRtoBGR TEGRA_CVTBGRTOBGR
@@ -1844,18 +1841,12 @@ TegraCvtColor_Invoker(bgrx2hsvf, bgrx2hsv, src_data + static_cast<size_t>(range.
#define cv_hal_cvtBGRtoGray TEGRA_CVTBGRTOGRAY
#undef cv_hal_cvtGraytoBGR
#define cv_hal_cvtGraytoBGR TEGRA_CVTGRAYTOBGR
#if 0 // bit-exact tests are failed
#undef cv_hal_cvtBGRtoYUV
#define cv_hal_cvtBGRtoYUV TEGRA_CVTBGRTOYUV
#endif
#undef cv_hal_cvtBGRtoHSV
#define cv_hal_cvtBGRtoHSV TEGRA_CVTBGRTOHSV
#if 0 // bit-exact tests are failed
#undef cv_hal_cvtTwoPlaneYUVtoBGR
#define cv_hal_cvtTwoPlaneYUVtoBGR TEGRA_CVT2PYUVTOBGR
#undef cv_hal_cvtTwoPlaneYUVtoBGREx
#define cv_hal_cvtTwoPlaneYUVtoBGREx TEGRA_CVT2PYUVTOBGR_EX
#endif
#endif // OPENCV_IMGPROC_HAL_INTERFACE_H
+5 -5
View File
@@ -1,8 +1,8 @@
# Binaries branch name: ffmpeg/4.x_20220524
# Binaries were created for OpenCV: d6e9616256b46bd59be0a93d397f6ab958d39cd2
ocv_update(FFMPEG_BINARIES_COMMIT "65ec04d4573dcdfa4531f0b9e67f35d8ffff873e")
ocv_update(FFMPEG_FILE_HASH_BIN32 "5573e2262ad1298e603122b7759fc2f6")
ocv_update(FFMPEG_FILE_HASH_BIN64 "5f9e2b2e04c15f080f40e844de80c867")
# Binaries branch name: ffmpeg/master_20210608
# Binaries were created for OpenCV: eaa9228a4fdfb9c2465aea65a50ce2d16b55dce0
ocv_update(FFMPEG_BINARIES_COMMIT "213fcd5d4897319a83207406036c4a5957fba010")
ocv_update(FFMPEG_FILE_HASH_BIN32 "bab661341c30862fa88627130219c0a5")
ocv_update(FFMPEG_FILE_HASH_BIN64 "ac99f9767a83103c31709628af685924")
ocv_update(FFMPEG_FILE_HASH_CMAKE "8862c87496e2e8c375965e1277dee1c7")
function(download_win_ffmpeg script_var)
-1
View File
@@ -54,7 +54,6 @@ set_target_properties(${ITT_LIBRARY} PROPERTIES
)
ocv_warnings_disable(CMAKE_C_FLAGS -Wundef -Wsign-compare)
ocv_warnings_disable(CMAKE_C_FLAGS -Wstrict-prototypes) # clang15
if(ENABLE_SOLUTION_FOLDERS)
set_target_properties(${ITT_LIBRARY} PROPERTIES FOLDER "3rdparty")
+2 -2
View File
@@ -4,9 +4,9 @@ ocv_warnings_disable(CMAKE_C_FLAGS -Wunused-parameter -Wsign-compare -Wshorten-6
set(VERSION_MAJOR 2)
set(VERSION_MINOR 1)
set(VERSION_REVISION 2)
set(VERSION_REVISION 0)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REVISION})
set(LIBJPEG_TURBO_VERSION_NUMBER 2001002)
set(LIBJPEG_TURBO_VERSION_NUMBER 2001000)
string(TIMESTAMP BUILD "opencv-${OPENCV_VERSION}-libjpeg-turbo")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
-10
View File
@@ -40,13 +40,3 @@
#define HAVE_BITSCANFORWARD
#endif
#endif
#if defined(__has_attribute)
#if __has_attribute(fallthrough)
#define FALLTHROUGH __attribute__((fallthrough));
#else
#define FALLTHROUGH
#endif
#else
#define FALLTHROUGH
#endif
+2 -3
View File
@@ -44,9 +44,8 @@
* flags (this defines __thumb__).
*/
/* NOTE: Both GCC and Clang define __GNUC__ */
#if (defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__))) || \
defined(_M_ARM) || defined(_M_ARM64)
#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || \
defined(_M_ARM64)
#if !defined(__thumb__) || defined(__thumb2__)
#define USE_CLZ_INTRINSIC
#endif
+1 -1
View File
@@ -493,7 +493,7 @@ prepare_for_pass(j_compress_ptr cinfo)
master->pass_type = output_pass;
master->pass_number++;
#endif
FALLTHROUGH /*FALLTHROUGH*/
/*FALLTHROUGH*/
case output_pass:
/* Do a data-output pass. */
/* We need not repeat per-scan setup if prior optimization pass did it. */
+4 -6
View File
@@ -7,7 +7,6 @@
* Copyright (C) 2011, 2015, 2018, 2021, D. R. Commander.
* Copyright (C) 2016, 2018, Matthieu Darbois.
* Copyright (C) 2020, Arm Limited.
* Copyright (C) 2021, Alex Richardson.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -53,9 +52,8 @@
* flags (this defines __thumb__).
*/
/* NOTE: Both GCC and Clang define __GNUC__ */
#if (defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__))) || \
defined(_M_ARM) || defined(_M_ARM64)
#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || \
defined(_M_ARM64)
#if !defined(__thumb__) || defined(__thumb2__)
#define USE_CLZ_INTRINSIC
#endif
@@ -681,7 +679,7 @@ encode_mcu_AC_first(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
emit_restart(entropy, entropy->next_restart_num);
#ifdef WITH_SIMD
cvalue = values = (JCOEF *)PAD((JUINTPTR)values_unaligned, 16);
cvalue = values = (JCOEF *)PAD((size_t)values_unaligned, 16);
#else
/* Not using SIMD, so alignment is not needed */
cvalue = values = values_unaligned;
@@ -946,7 +944,7 @@ encode_mcu_AC_refine(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
emit_restart(entropy, entropy->next_restart_num);
#ifdef WITH_SIMD
cabsvalue = absvalues = (JCOEF *)PAD((JUINTPTR)absvalues_unaligned, 16);
cabsvalue = absvalues = (JCOEF *)PAD((size_t)absvalues_unaligned, 16);
#else
/* Not using SIMD, so alignment is not needed */
cabsvalue = absvalues = absvalues_unaligned;
+1 -2
View File
@@ -23,7 +23,6 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "jdmaster.h"
#include "jconfigint.h"
/*
@@ -309,7 +308,7 @@ jpeg_consume_input(j_decompress_ptr cinfo)
/* Initialize application's data source module */
(*cinfo->src->init_source) (cinfo);
cinfo->global_state = DSTATE_INHEADER;
FALLTHROUGH /*FALLTHROUGH*/
/*FALLTHROUGH*/
case DSTATE_INHEADER:
retcode = (*cinfo->inputctl->consume_input) (cinfo);
if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */
+1 -10
View File
@@ -584,7 +584,7 @@ decode_mcu_slow(j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
* behavior is, to the best of our understanding, innocuous, and it is
* unclear how to work around it without potentially affecting
* performance. Thus, we (hopefully temporarily) suppress UBSan integer
* overflow errors for this function and decode_mcu_fast().
* overflow errors for this function.
*/
s += state.last_dc_val[ci];
state.last_dc_val[ci] = s;
@@ -651,12 +651,6 @@ decode_mcu_slow(j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
}
#if defined(__has_feature)
#if __has_feature(undefined_behavior_sanitizer)
__attribute__((no_sanitize("signed-integer-overflow"),
no_sanitize("unsigned-integer-overflow")))
#endif
#endif
LOCAL(boolean)
decode_mcu_fast(j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
{
@@ -687,9 +681,6 @@ decode_mcu_fast(j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
if (entropy->dc_needed[blkn]) {
int ci = cinfo->MCU_membership[blkn];
/* Refer to the comment in decode_mcu_slow() regarding the supression of
* a UBSan integer overflow error in this line of code.
*/
s += state.last_dc_val[ci];
state.last_dc_val[ci] = s;
if (block)
+2 -3
View File
@@ -18,7 +18,6 @@
#include "jinclude.h"
#include "jdmainct.h"
#include "jconfigint.h"
/*
@@ -361,7 +360,7 @@ process_data_context_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
main_ptr->context_state = CTX_PREPARE_FOR_IMCU;
if (*out_row_ctr >= out_rows_avail)
return; /* Postprocessor exactly filled output buf */
FALLTHROUGH /*FALLTHROUGH*/
/*FALLTHROUGH*/
case CTX_PREPARE_FOR_IMCU:
/* Prepare to process first M-1 row groups of this iMCU row */
main_ptr->rowgroup_ctr = 0;
@@ -372,7 +371,7 @@ process_data_context_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
if (main_ptr->iMCU_row_ctr == cinfo->total_iMCU_rows)
set_bottom_pointers(cinfo);
main_ptr->context_state = CTX_PROCESS_IMCU;
FALLTHROUGH /*FALLTHROUGH*/
/*FALLTHROUGH*/
case CTX_PROCESS_IMCU:
/* Call postprocessor using previously set pointers */
(*cinfo->post->post_process_data) (cinfo,
+3 -3
View File
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2016, 2021, D. R. Commander.
* Copyright (C) 2016, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -1032,7 +1032,7 @@ free_pool(j_common_ptr cinfo, int pool_id)
large_pool_ptr next_lhdr_ptr = lhdr_ptr->next;
space_freed = lhdr_ptr->bytes_used +
lhdr_ptr->bytes_left +
sizeof(large_pool_hdr) + ALIGN_SIZE - 1;
sizeof(large_pool_hdr);
jpeg_free_large(cinfo, (void *)lhdr_ptr, space_freed);
mem->total_space_allocated -= space_freed;
lhdr_ptr = next_lhdr_ptr;
@@ -1045,7 +1045,7 @@ free_pool(j_common_ptr cinfo, int pool_id)
while (shdr_ptr != NULL) {
small_pool_ptr next_shdr_ptr = shdr_ptr->next;
space_freed = shdr_ptr->bytes_used + shdr_ptr->bytes_left +
sizeof(small_pool_hdr) + ALIGN_SIZE - 1;
sizeof(small_pool_hdr);
jpeg_free_small(cinfo, (void *)shdr_ptr, space_freed);
mem->total_space_allocated -= space_freed;
shdr_ptr = next_shdr_ptr;
+1 -14
View File
@@ -5,9 +5,8 @@
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 1997-2009 by Guido Vollbeding.
* libjpeg-turbo Modifications:
* Copyright (C) 2015-2016, 2019, 2021, D. R. Commander.
* Copyright (C) 2015-2016, 2019, D. R. Commander.
* Copyright (C) 2015, Google, Inc.
* Copyright (C) 2021, Alex Richardson.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -48,18 +47,6 @@ typedef enum { /* Operating modes for buffer controllers */
/* JLONG must hold at least signed 32-bit values. */
typedef long JLONG;
/* JUINTPTR must hold pointer values. */
#ifdef __UINTPTR_TYPE__
/*
* __UINTPTR_TYPE__ is GNU-specific and available in GCC 4.6+ and Clang 3.0+.
* Fortunately, that is sufficient to support the few architectures for which
* sizeof(void *) != sizeof(size_t). The only other options would require C99
* or Clang-specific builtins.
*/
typedef __UINTPTR_TYPE__ JUINTPTR;
#else
typedef size_t JUINTPTR;
#endif
/*
* Left shift macro that handles a negative operand without causing any
+1 -5
View File
@@ -77,11 +77,7 @@ endif(MSVC)
add_library(${PNG_LIBRARY} STATIC ${OPENCV_3RDPARTY_EXCLUDE_FROM_ALL} ${lib_srcs} ${lib_hdrs})
target_link_libraries(${PNG_LIBRARY} ${ZLIB_LIBRARIES})
ocv_warnings_disable(CMAKE_C_FLAGS -Wundef -Wcast-align -Wimplicit-fallthrough -Wunused-parameter -Wsign-compare
-Wmaybe-uninitialized
-Wnull-pointer-subtraction # clang15
-Wunused-but-set-variable # clang15
)
ocv_warnings_disable(CMAKE_C_FLAGS -Wundef -Wcast-align -Wimplicit-fallthrough -Wunused-parameter -Wsign-compare)
set_target_properties(${PNG_LIBRARY}
PROPERTIES OUTPUT_NAME ${PNG_LIBRARY}
+1 -3
View File
@@ -452,10 +452,8 @@ ocv_warnings_disable(CMAKE_C_FLAGS -Wno-unused-but-set-variable -Wmissing-protot
-Wcast-align -Wshadow -Wno-maybe-uninitialized -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast
-Wmisleading-indentation
-Wimplicit-fallthrough
-Wunused-parameter # clang
-Warray-parameter
-Wstrict-prototypes # clang15
)
ocv_warnings_disable(CMAKE_C_FLAGS -Wunused-parameter) # clang
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wmissing-declarations -Wunused-parameter -Wmissing-prototypes
-Wundef # tiffiop.h: #if __clang_major__ >= 4
)
-73
View File
@@ -1,73 +0,0 @@
set(TIMVX_COMMIT_HASH "1d9c7ab941b3d8d9c4d28d80058402725731e3d6")
set(OCV_TIMVX_DIR "${OpenCV_BINARY_DIR}/3rdparty/libtim-vx")
set(OCV_TIMVX_SOURCE_PATH "${OCV_TIMVX_DIR}/TIM-VX-${TIMVX_COMMIT_HASH}")
# Download TIM-VX source code
if(EXISTS "${OCV_TIMVX_SOURCE_PATH}")
message(STATUS "TIM-VX: Use cache of TIM-VX source code at ${OCV_TIMVX_SOURCE_PATH}")
set(TIMVX_FOUND ON)
else()
set(OCV_TIMVX_FILENAME "${TIMVX_COMMIT_HASH}.zip")
set(OCV_TIMVX_URL "https://github.com/VeriSilicon/TIM-VX/archive/")
set(timvx_zip_md5sum 92619cc4498014ac7a09834d5e33ebd5)
ocv_download(FILENAME ${OCV_TIMVX_FILENAME}
HASH ${timvx_zip_md5sum}
URL "${OCV_TIMVX_URL}"
DESTINATION_DIR "${OCV_TIMVX_DIR}"
ID "TIM-VX"
STATUS res
UNPACK RELATIVE_URL)
if(res)
set(TIMVX_FOUND ON)
message(STATUS "TIM-VX: Source code downloaded at ${OCV_TIMVX_SOURCE_PATH}.")
else()
set(TIMVX_FOUND OFF)
message(STATUS "TIM-VX: Failed to download source code from github. Turning off TIMVX_FOUND")
return()
endif()
endif()
# set VIVANTE SDK especially for x86_64 which comes along with TIM-VX source code
if(CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64)
set(VIVANTE_SDK_DIR "${OCV_TIMVX_SOURCE_PATH}/prebuilt-sdk/x86_64_linux")
message(STATUS "TIM-VX: Build from source using prebuilt x86_64 VIVANTE SDK.")
endif()
# Verify if requested VIVANTE SDK libraries are all found
find_vivante_sdk_libs(missing ${VIVANTE_SDK_DIR})
if(missing)
message(STATUS "TIM-VX: Failed to find ${missing} in ${VIVANTE_SDK_DIR}/lib. Turning off TIMVX_VIV_FOUND")
set(TIMVX_VIV_FOUND OFF)
else()
message(STATUS "TIM-VX: dependent VIVANTE SDK libraries are found at ${VIVANTE_SDK_DIR}/lib.")
set(TIMVX_VIV_FOUND ON)
endif()
if(TIMVX_VIV_FOUND)
# vars used by TIM-VX CMake scripts
set(EXTERNAL_VIV_SDK "${VIVANTE_SDK_DIR}" CACHE INTERNAL "" FORCE)
set(VIV_SDK_DRIVER_PREFIX "lib" CACHE INTERNAL "" FORCE)
endif()
if(TIMVX_FOUND AND TIMVX_VIV_FOUND)
set(BUILD_TIMVX ON)
else()
return()
endif()
if(BUILD_TIMVX)
set(HAVE_TIMVX 1)
ocv_warnings_disable(CMAKE_C_FLAGS -Wunused-parameter -Wstrict-prototypes -Wundef -Wsign-compare -Wmissing-prototypes -Wmissing-declarations -Wstrict-aliasing -Wunused-but-set-variable -Wmaybe-uninitialized -Wshadow -Wsuggest-override -Wswitch)
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wunused-parameter -Wstrict-prototypes -Wundef -Wsign-compare -Wunused-but-set-variable -Wshadow -Wsuggest-override -Wmissing-declarations -Wswitch)
set(TIMVX_INC_DIR "${OCV_TIMVX_SOURCE_PATH}/include" CACHE INTERNAL "TIM-VX include directory")
if(EXISTS "${OCV_TIMVX_SOURCE_PATH}/CMakeLists.txt")
add_subdirectory("${OCV_TIMVX_SOURCE_PATH}" "${OCV_TIMVX_DIR}/build")
else()
message(WARNING "TIM-VX: Missing 'CMakeLists.txt' in the source code: ${OCV_TIMVX_SOURCE_PATH}")
endif()
ocv_install_target(tim-vx EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev)
set(TIMVX_LIB "tim-vx")
endif()
+1 -4
View File
@@ -32,9 +32,7 @@ endif()
# Define the library target:
# ----------------------------------------------------------------------------------
if(NOT OPENCV_DISABLE_THREAD_SUPPORT)
add_definitions(-DWEBP_USE_THREAD)
endif()
add_definitions(-DWEBP_USE_THREAD)
add_library(${WEBP_LIBRARY} STATIC ${OPENCV_3RDPARTY_EXCLUDE_FROM_ALL} ${lib_srcs} ${lib_hdrs})
if(ANDROID)
@@ -45,7 +43,6 @@ ocv_warnings_disable(CMAKE_C_FLAGS -Wunused-variable -Wunused-function -Wshadow
-Wmissing-prototypes # clang
-Wmissing-declarations # gcc
-Wimplicit-fallthrough
-Wunused-but-set-variable # clang15
)
ocv_warnings_disable(CMAKE_C_FLAGS /wd4244 /wd4267) # vs2005
-1
View File
@@ -13,7 +13,6 @@ project(openjpeg C)
ocv_warnings_disable(CMAKE_C_FLAGS
-Wimplicit-const-int-float-conversion # clang
-Wunused-but-set-variable # clang15
)
#-----------------------------------------------------------------------------
+1 -1
View File
@@ -77,7 +77,7 @@ E.g. external ref-counting is implemented for 1.0 version and native OpenVX one
Also there are some **C++ 11** features are used (e.g. rvalue ref-s) when their availability is detected at ***compile time***.
C++ exceptions are used for errors indication instead of return codes. There are two types of exceptions are defined: `RuntimeError` is thrown when OpenVX C call returned unsuccessful result and `WrapperError` is thrown when a problem is occurred in the wrappers code. Both exception calsses are derived from `std::exception` (actually from its inheritants).
C++ exceptions are used for errors indication instead of return codes. There are two types of exceptions are defined: `RuntimeError` is thrown when OpenVX C call returned unsuccessful result and `WrapperError` is thrown when a problem is occured in the wrappers code. Both exception calsses are derived from `std::exception` (actually from its inheritants).
The so called **OpenVX objects** (e.g. `vx_image`) are represented as C++ classes in wrappers.
All these classes use automatic ref-counting that allows development of exception-safe code.
+5 -9
View File
@@ -923,11 +923,6 @@ int ovx_hal_cvtGraytoBGR(const uchar * a, size_t astep, uchar * b, size_t bstep,
}
int ovx_hal_cvtTwoPlaneYUVtoBGR(const uchar * a, size_t astep, uchar * b, size_t bstep, int w, int h, int bcn, bool swapBlue, int uIdx)
{
return ovx_hal_cvtTwoPlaneYUVtoBGREx(a, astep, a + h * astep, astep, b, bstep, w, h, bcn, swapBlue, uIdx);
}
int ovx_hal_cvtTwoPlaneYUVtoBGREx(const uchar * a, size_t astep, const uchar * b, size_t bstep, uchar * c, size_t cstep, int w, int h, int bcn, bool swapBlue, int uIdx)
{
if (skipSmallImages<VX_KERNEL_COLOR_CONVERT>(w, h))
return CV_HAL_ERROR_NOT_IMPLEMENTED;
@@ -938,7 +933,8 @@ int ovx_hal_cvtTwoPlaneYUVtoBGREx(const uchar * a, size_t astep, const uchar * b
if (w & 1 || h & 1) // It's not described in spec but sample implementation unable to convert odd sized images
return CV_HAL_ERROR_NOT_IMPLEMENTED;
refineStep(w, h, uIdx ? VX_DF_IMAGE_NV21 : VX_DF_IMAGE_NV12, astep);
refineStep(w, h, bcn == 3 ? VX_DF_IMAGE_RGB : VX_DF_IMAGE_RGBX, bstep);
try
{
ivx::Context ctx = getOpenVXHALContext();
@@ -947,8 +943,8 @@ int ovx_hal_cvtTwoPlaneYUVtoBGREx(const uchar * a, size_t astep, const uchar * b
std::vector<void *> ptrs;
addr.push_back(ivx::Image::createAddressing(w, h, 1, (vx_int32)astep));
ptrs.push_back((void*)a);
addr.push_back(ivx::Image::createAddressing(w / 2, h / 2, 2, (vx_int32)bstep));
ptrs.push_back((void*)b);
addr.push_back(ivx::Image::createAddressing(w / 2, h / 2, 2, (vx_int32)astep));
ptrs.push_back((void*)(a + h * astep));
vxImage
ia = ivx::Image::createFromHandle(ctx, uIdx ? VX_DF_IMAGE_NV21 : VX_DF_IMAGE_NV12, addr, ptrs);
@@ -956,7 +952,7 @@ int ovx_hal_cvtTwoPlaneYUVtoBGREx(const uchar * a, size_t astep, const uchar * b
return CV_HAL_ERROR_NOT_IMPLEMENTED; // OpenCV store NV12/NV21 as RANGE_RESTRICTED while OpenVX expect RANGE_FULL
vxImage
ib = ivx::Image::createFromHandle(ctx, bcn == 3 ? VX_DF_IMAGE_RGB : VX_DF_IMAGE_RGBX,
ivx::Image::createAddressing(w, h, bcn, (vx_int32)cstep), c);
ivx::Image::createAddressing(w, h, bcn, (vx_int32)bstep), b);
ivx::IVX_CHECK_STATUS(vxuColorConvert(ctx, ia, ib));
}
catch (ivx::RuntimeError & e)
-3
View File
@@ -49,7 +49,6 @@ int ovx_hal_morph(cvhalFilter2D *filter_context, uchar *a, size_t astep, uchar *
int ovx_hal_cvtBGRtoBGR(const uchar * a, size_t astep, uchar * b, size_t bstep, int w, int h, int depth, int acn, int bcn, bool swapBlue);
int ovx_hal_cvtGraytoBGR(const uchar * a, size_t astep, uchar * b, size_t bstep, int w, int h, int depth, int bcn);
int ovx_hal_cvtTwoPlaneYUVtoBGR(const uchar * a, size_t astep, uchar * b, size_t bstep, int w, int h, int bcn, bool swapBlue, int uIdx);
int ovx_hal_cvtTwoPlaneYUVtoBGREx(const uchar * a, size_t astep, const uchar * b, size_t bstep, uchar * c, size_t cstep, int w, int h, int bcn, bool swapBlue, int uIdx);
int ovx_hal_cvtThreePlaneYUVtoBGR(const uchar * a, size_t astep, uchar * b, size_t bstep, int w, int h, int bcn, bool swapBlue, int uIdx);
int ovx_hal_cvtBGRtoThreePlaneYUV(const uchar * a, size_t astep, uchar * b, size_t bstep, int w, int h, int acn, bool swapBlue, int uIdx);
int ovx_hal_cvtOnePlaneYUVtoBGR(const uchar * a, size_t astep, uchar * b, size_t bstep, int w, int h, int bcn, bool swapBlue, int uIdx, int ycn);
@@ -131,8 +130,6 @@ int ovx_hal_integral(int depth, int sdepth, int, const uchar * a, size_t astep,
#define cv_hal_cvtGraytoBGR ovx_hal_cvtGraytoBGR
#undef cv_hal_cvtTwoPlaneYUVtoBGR
#define cv_hal_cvtTwoPlaneYUVtoBGR ovx_hal_cvtTwoPlaneYUVtoBGR
#undef cv_hal_cvtTwoPlaneYUVtoBGREx
#define cv_hal_cvtTwoPlaneYUVtoBGREx ovx_hal_cvtTwoPlaneYUVtoBGREx
#undef cv_hal_cvtThreePlaneYUVtoBGR
#define cv_hal_cvtThreePlaneYUVtoBGR ovx_hal_cvtThreePlaneYUVtoBGR
#undef cv_hal_cvtBGRtoThreePlaneYUV
+50 -56
View File
@@ -13,9 +13,6 @@ if(MSVC)
/wd4701 /wd4703 # potentially uninitialized local/pointer variable 'value' used
/wd4505 # unreferenced local function has been removed
)
if(MSVC_VERSION LESS 1920) # MSVS 2015/2017
ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4309) # 'static_cast': truncation of constant value
endif()
else()
#NOTE: -Wno-invalid-offsetof was used as solution for invalid offset warning on protobuf #3450
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-deprecated -Wmissing-prototypes -Wmissing-declarations -Wshadow
@@ -52,101 +49,98 @@ endfunction()
set(PROTOBUF_ROOT "${CMAKE_CURRENT_LIST_DIR}")
if(MSVC)
set(ATOMICOPS_INTERNALS ${PROTOBUF_ROOT}/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc)
else()
set(ATOMICOPS_INTERNALS ${PROTOBUF_ROOT}/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc)
endif()
append_if_exist(Protobuf_SRCS
# libprotobuf-lite
${PROTOBUF_ROOT}/src/google/protobuf/any_lite.cc
${PROTOBUF_ROOT}/src/google/protobuf/arena.cc
${PROTOBUF_ROOT}/src/google/protobuf/arenastring.cc
${PROTOBUF_ROOT}/src/google/protobuf/extension_set.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/generated_enum_util.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/generated_message_table_driven_lite.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/generated_message_tctable_lite.cc
${PROTOBUF_ROOT}/src/google/protobuf/generated_message_table_driven_lite.cc
${PROTOBUF_ROOT}/src/google/protobuf/generated_message_util.cc
${PROTOBUF_ROOT}/src/google/protobuf/implicit_weak_message.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/inlined_string_field.cc
${PROTOBUF_ROOT}/src/google/protobuf/io/coded_stream.cc
${PROTOBUF_ROOT}/src/google/protobuf/io/io_win32.cc
${PROTOBUF_ROOT}/src/google/protobuf/io/strtod.cc
${PROTOBUF_ROOT}/src/google/protobuf/io/zero_copy_stream.cc
${PROTOBUF_ROOT}/src/google/protobuf/io/zero_copy_stream_impl.cc
${PROTOBUF_ROOT}/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
${PROTOBUF_ROOT}/src/google/protobuf/map.cc
${PROTOBUF_ROOT}/src/google/protobuf/message_lite.cc
${PROTOBUF_ROOT}/src/google/protobuf/parse_context.cc
${PROTOBUF_ROOT}/src/google/protobuf/repeated_field.cc
${PROTOBUF_ROOT}/src/google/protobuf/repeated_ptr_field.cc
${ATOMICOPS_INTERNALS}
${PROTOBUF_ROOT}/src/google/protobuf/stubs/bytestream.cc
${PROTOBUF_ROOT}/src/google/protobuf/stubs/common.cc
${PROTOBUF_ROOT}/src/google/protobuf/stubs/int128.cc
${PROTOBUF_ROOT}/src/google/protobuf/stubs/io_win32.cc
${PROTOBUF_ROOT}/src/google/protobuf/stubs/once.cc
${PROTOBUF_ROOT}/src/google/protobuf/stubs/status.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/stubs/statusor.cc
${PROTOBUF_ROOT}/src/google/protobuf/stubs/statusor.cc
${PROTOBUF_ROOT}/src/google/protobuf/stubs/stringpiece.cc
${PROTOBUF_ROOT}/src/google/protobuf/stubs/stringprintf.cc
${PROTOBUF_ROOT}/src/google/protobuf/stubs/structurally_valid.cc
${PROTOBUF_ROOT}/src/google/protobuf/stubs/strutil.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/stubs/time.cc
${PROTOBUF_ROOT}/src/google/protobuf/stubs/time.cc
${PROTOBUF_ROOT}/src/google/protobuf/wire_format_lite.cc
# libprotobuf
${PROTOBUF_ROOT}/src/google/protobuf/any.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/any.pb.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/api.pb.cc
${PROTOBUF_ROOT}/src/google/protobuf/any.pb.cc
${PROTOBUF_ROOT}/src/google/protobuf/api.pb.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/compiler/importer.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/compiler/parser.cc
${PROTOBUF_ROOT}/src/google/protobuf/descriptor.cc
${PROTOBUF_ROOT}/src/google/protobuf/descriptor.pb.cc
${PROTOBUF_ROOT}/src/google/protobuf/descriptor_database.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/duration.pb.cc
${PROTOBUF_ROOT}/src/google/protobuf/duration.pb.cc
${PROTOBUF_ROOT}/src/google/protobuf/dynamic_message.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/empty.pb.cc
${PROTOBUF_ROOT}/src/google/protobuf/empty.pb.cc
${PROTOBUF_ROOT}/src/google/protobuf/extension_set_heavy.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/field_mask.pb.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/generated_message_bases.cc
${PROTOBUF_ROOT}/src/google/protobuf/field_mask.pb.cc
${PROTOBUF_ROOT}/src/google/protobuf/generated_message_reflection.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/generated_message_table_driven.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/generated_message_tctable_full.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/io/gzip_stream.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/io/printer.cc
${PROTOBUF_ROOT}/src/google/protobuf/generated_message_table_driven.cc
${PROTOBUF_ROOT}/src/google/protobuf/io/gzip_stream.cc
${PROTOBUF_ROOT}/src/google/protobuf/io/printer.cc
${PROTOBUF_ROOT}/src/google/protobuf/io/strtod.cc
${PROTOBUF_ROOT}/src/google/protobuf/io/tokenizer.cc
${PROTOBUF_ROOT}/src/google/protobuf/io/zero_copy_stream_impl.cc
${PROTOBUF_ROOT}/src/google/protobuf/map_field.cc
${PROTOBUF_ROOT}/src/google/protobuf/message.cc
${PROTOBUF_ROOT}/src/google/protobuf/reflection_ops.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/service.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/source_context.pb.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/struct.pb.cc
${PROTOBUF_ROOT}/src/google/protobuf/service.cc
${PROTOBUF_ROOT}/src/google/protobuf/source_context.pb.cc
${PROTOBUF_ROOT}/src/google/protobuf/struct.pb.cc
${PROTOBUF_ROOT}/src/google/protobuf/stubs/mathlimits.cc
${PROTOBUF_ROOT}/src/google/protobuf/stubs/substitute.cc
${PROTOBUF_ROOT}/src/google/protobuf/text_format.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/timestamp.pb.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/type.pb.cc
${PROTOBUF_ROOT}/src/google/protobuf/timestamp.pb.cc
${PROTOBUF_ROOT}/src/google/protobuf/type.pb.cc
${PROTOBUF_ROOT}/src/google/protobuf/unknown_field_set.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/delimited_message_util.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/field_comparator.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/field_mask_util.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/datapiece.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/default_value_objectwriter.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/delimited_message_util.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/field_comparator.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/field_mask_util.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/internal/datapiece.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/internal/default_value_objectwriter.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/error_listener.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/field_mask_utility.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/json_escaping.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/json_objectwriter.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/json_stream_parser.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/object_writer.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/proto_writer.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/protostream_objectsource.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/protostream_objectwriter.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/type_info.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/utility.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/json_util.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/message_differencer.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/time_util.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/type_resolver_util.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/internal/field_mask_utility.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/internal/json_escaping.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/internal/json_objectwriter.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/internal/json_stream_parser.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/internal/object_writer.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/internal/proto_writer.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/internal/protostream_objectsource.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/internal/protostream_objectwriter.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/internal/type_info.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/type_info_test_helper.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/internal/utility.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/json_util.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/message_differencer.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/time_util.cc
${PROTOBUF_ROOT}/src/google/protobuf/util/type_resolver_util.cc
${PROTOBUF_ROOT}/src/google/protobuf/wire_format.cc
# ${PROTOBUF_ROOT}/src/google/protobuf/wrappers.pb.cc
${PROTOBUF_ROOT}/src/google/protobuf/wrappers.pb.cc
)
include_directories(BEFORE "${PROTOBUF_ROOT}/src") # ensure using of own headers: https://github.com/opencv/opencv/issues/13328
include_directories(BEFORE "${PROTOBUF_ROOT}/src") # ensure using if own headers: https://github.com/opencv/opencv/issues/13328
add_library(libprotobuf STATIC ${OPENCV_3RDPARTY_EXCLUDE_FROM_ALL} ${Protobuf_SRCS})
target_include_directories(libprotobuf SYSTEM PUBLIC $<BUILD_INTERFACE:${PROTOBUF_ROOT}/src>)
set_target_properties(libprotobuf
+11 -1
View File
@@ -1,4 +1,14 @@
Copyright 2008 Google Inc. All rights reserved.
This license applies to all parts of Protocol Buffers except the following:
- Atomicops support for generic gcc, located in
src/google/protobuf/stubs/atomicops_internals_generic_gcc.h.
This file is copyrighted by Red Hat Inc.
- Atomicops support for AIX/POWER, located in
src/google/protobuf/stubs/atomicops_internals_power.h.
This file is copyrighted by Bloomberg Finance LP.
Copyright 2014, Google Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
+1 -1
View File
@@ -1,3 +1,3 @@
Project: Protocol Buffers - Google's data interchange format
Source code: https://github.com/protocolbuffers/protobuf
Version: 3.19.1
Version: 3.5.2
+59 -28
View File
@@ -30,54 +30,85 @@
#include <google/protobuf/any.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/message.h>
#include <google/protobuf/port_def.inc>
namespace google {
namespace protobuf {
namespace internal {
bool AnyMetadata::PackFrom(Arena* arena, const Message& message) {
return PackFrom(arena, message, kTypeGoogleApisComPrefix);
namespace {
string GetTypeUrl(const Descriptor* message,
const string& type_url_prefix) {
if (!type_url_prefix.empty() &&
type_url_prefix[type_url_prefix.size() - 1] == '/') {
return type_url_prefix + message->full_name();
} else {
return type_url_prefix + "/" + message->full_name();
}
}
} // namespace
const char kAnyFullTypeName[] = "google.protobuf.Any";
const char kTypeGoogleApisComPrefix[] = "type.googleapis.com/";
const char kTypeGoogleProdComPrefix[] = "type.googleprod.com/";
AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value)
: type_url_(type_url), value_(value) {
}
bool AnyMetadata::PackFrom(Arena* arena, const Message& message,
StringPiece type_url_prefix) {
type_url_->Set(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString(),
GetTypeUrl(message.GetDescriptor()->full_name(), type_url_prefix), arena);
return message.SerializeToString(
value_->Mutable(ArenaStringPtr::EmptyDefault{}, arena));
void AnyMetadata::PackFrom(const Message& message) {
PackFrom(message, kTypeGoogleApisComPrefix);
}
void AnyMetadata::PackFrom(const Message& message,
const string& type_url_prefix) {
type_url_->SetNoArena(&::google::protobuf::internal::GetEmptyString(),
GetTypeUrl(message.GetDescriptor(), type_url_prefix));
message.SerializeToString(value_->MutableNoArena(
&::google::protobuf::internal::GetEmptyStringAlreadyInited()));
}
bool AnyMetadata::UnpackTo(Message* message) const {
if (!InternalIs(message->GetDescriptor()->full_name())) {
if (!InternalIs(message->GetDescriptor())) {
return false;
}
return message->ParseFromString(value_->Get());
return message->ParseFromString(value_->GetNoArena());
}
bool AnyMetadata::InternalIs(const Descriptor* descriptor) const {
const string type_url = type_url_->GetNoArena();
string full_name;
if (!ParseAnyTypeUrl(type_url, &full_name)) {
return false;
}
return full_name == descriptor->full_name();
}
bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) {
size_t pos = type_url.find_last_of("/");
if (pos == string::npos || pos + 1 == type_url.size()) {
return false;
}
*full_type_name = type_url.substr(pos + 1);
return true;
}
bool GetAnyFieldDescriptors(const Message& message,
const FieldDescriptor** type_url_field,
const FieldDescriptor** value_field) {
const Descriptor* descriptor = message.GetDescriptor();
if (descriptor->full_name() != kAnyFullTypeName) {
return false;
}
*type_url_field = descriptor->FindFieldByNumber(1);
*value_field = descriptor->FindFieldByNumber(2);
return (*type_url_field != nullptr &&
(*type_url_field)->type() == FieldDescriptor::TYPE_STRING &&
*value_field != nullptr &&
(*value_field)->type() == FieldDescriptor::TYPE_BYTES);
const Descriptor* descriptor = message.GetDescriptor();
if (descriptor->full_name() != kAnyFullTypeName) {
return false;
}
*type_url_field = descriptor->FindFieldByNumber(1);
*value_field = descriptor->FindFieldByNumber(2);
return (*type_url_field != NULL &&
(*type_url_field)->type() == FieldDescriptor::TYPE_STRING &&
*value_field != NULL &&
(*value_field)->type() == FieldDescriptor::TYPE_BYTES);
}
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
+17 -66
View File
@@ -34,89 +34,49 @@
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/port_def.inc>
namespace google {
namespace protobuf {
class FieldDescriptor;
class Message;
namespace internal {
extern const char kAnyFullTypeName[]; // "google.protobuf.Any".
extern const char kTypeGoogleApisComPrefix[]; // "type.googleapis.com/".
extern const char kTypeGoogleProdComPrefix[]; // "type.googleprod.com/".
std::string GetTypeUrl(StringPiece message_name,
StringPiece type_url_prefix);
// Helper class used to implement google::protobuf::Any.
class PROTOBUF_EXPORT AnyMetadata {
class LIBPROTOBUF_EXPORT AnyMetadata {
typedef ArenaStringPtr UrlType;
typedef ArenaStringPtr ValueType;
public:
// AnyMetadata does not take ownership of "type_url" and "value".
constexpr AnyMetadata(UrlType* type_url, ValueType* value)
: type_url_(type_url), value_(value) {}
AnyMetadata(UrlType* type_url, ValueType* value);
// Packs a message using the default type URL prefix: "type.googleapis.com".
// The resulted type URL will be "type.googleapis.com/<message_full_name>".
// Returns false if serializing the message failed.
template <typename T>
bool PackFrom(Arena* arena, const T& message) {
return InternalPackFrom(arena, message, kTypeGoogleApisComPrefix,
T::FullMessageName());
}
bool PackFrom(Arena* arena, const Message& message);
void PackFrom(const Message& message);
// Packs a message using the given type URL prefix. The type URL will be
// constructed by concatenating the message type's full name to the prefix
// with an optional "/" separator if the prefix doesn't already end with "/".
// with an optional "/" separator if the prefix doesn't already end up "/".
// For example, both PackFrom(message, "type.googleapis.com") and
// PackFrom(message, "type.googleapis.com/") yield the same result type
// URL: "type.googleapis.com/<message_full_name>".
// Returns false if serializing the message failed.
template <typename T>
bool PackFrom(Arena* arena, const T& message,
StringPiece type_url_prefix) {
return InternalPackFrom(arena, message, type_url_prefix,
T::FullMessageName());
}
bool PackFrom(Arena* arena, const Message& message,
StringPiece type_url_prefix);
void PackFrom(const Message& message, const string& type_url_prefix);
// Unpacks the payload into the given message. Returns false if the message's
// type doesn't match the type specified in the type URL (i.e., the full
// name after the last "/" of the type URL doesn't match the message's actual
// full name) or parsing the payload has failed.
template <typename T>
bool UnpackTo(T* message) const {
return InternalUnpackTo(T::FullMessageName(), message);
}
bool UnpackTo(Message* message) const;
// Checks whether the type specified in the type URL matches the given type.
// A type is considered matching if its full name matches the full name after
// A type is consdiered matching if its full name matches the full name after
// the last "/" in the type URL.
template <typename T>
template<typename T>
bool Is() const {
return InternalIs(T::FullMessageName());
return InternalIs(T::default_instance().GetDescriptor());
}
private:
bool InternalPackFrom(Arena* arena, const MessageLite& message,
StringPiece type_url_prefix,
StringPiece type_name);
bool InternalUnpackTo(StringPiece type_name,
MessageLite* message) const;
bool InternalIs(StringPiece type_name) const;
bool InternalIs(const Descriptor* message) const;
UrlType* type_url_;
ValueType* value_;
@@ -124,22 +84,15 @@ class PROTOBUF_EXPORT AnyMetadata {
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AnyMetadata);
};
extern const char kAnyFullTypeName[]; // "google.protobuf.Any".
extern const char kTypeGoogleApisComPrefix[]; // "type.googleapis.com/".
extern const char kTypeGoogleProdComPrefix[]; // "type.googleprod.com/".
// Get the proto type name from Any::type_url value. For example, passing
// "type.googleapis.com/rpc.QueryOrigin" will return "rpc.QueryOrigin" in
// *full_type_name. Returns false if the type_url does not have a "/"
// in the type url separating the full type name.
//
// NOTE: this function is available publicly as:
// google::protobuf::Any() // static method on the generated message type.
bool ParseAnyTypeUrl(StringPiece type_url, std::string* full_type_name);
// Get the proto type name and prefix from Any::type_url value. For example,
// passing "type.googleapis.com/rpc.QueryOrigin" will return
// "type.googleapis.com/" in *url_prefix and "rpc.QueryOrigin" in
// *full_type_name. Returns false if the type_url does not have a "/" in the
// type url separating the full type name.
bool ParseAnyTypeUrl(StringPiece type_url, std::string* url_prefix,
std::string* full_type_name);
bool ParseAnyTypeUrl(const string& type_url, string* full_type_name);
// See if message is of type google.protobuf.Any, if so, return the descriptors
// for "type_url" and "value" fields.
@@ -149,8 +102,6 @@ bool GetAnyFieldDescriptors(const Message& message,
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_ANY_H__
+440
View File
@@ -0,0 +1,440 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/protobuf/any.proto
#include <google/protobuf/any.pb.h>
#include <algorithm>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/wire_format.h>
// This is a temporary google only hack
#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
#include "third_party/protobuf/version.h"
#endif
// @@protoc_insertion_point(includes)
namespace google {
namespace protobuf {
class AnyDefaultTypeInternal {
public:
::google::protobuf::internal::ExplicitlyConstructed<Any>
_instance;
} _Any_default_instance_;
} // namespace protobuf
} // namespace google
namespace protobuf_google_2fprotobuf_2fany_2eproto {
void InitDefaultsAnyImpl() {
GOOGLE_PROTOBUF_VERIFY_VERSION;
#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
::google::protobuf::internal::InitProtobufDefaultsForceUnique();
#else
::google::protobuf::internal::InitProtobufDefaults();
#endif // GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
{
void* ptr = &::google::protobuf::_Any_default_instance_;
new (ptr) ::google::protobuf::Any();
::google::protobuf::internal::OnShutdownDestroyMessage(ptr);
}
::google::protobuf::Any::InitAsDefaultInstance();
}
void InitDefaultsAny() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &InitDefaultsAnyImpl);
}
::google::protobuf::Metadata file_level_metadata[1];
const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
~0u, // no _has_bits_
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::Any, _internal_metadata_),
~0u, // no _extensions_
~0u, // no _oneof_case_
~0u, // no _weak_field_map_
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::Any, type_url_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::Any, value_),
};
static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
{ 0, -1, sizeof(::google::protobuf::Any)},
};
static ::google::protobuf::Message const * const file_default_instances[] = {
reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::_Any_default_instance_),
};
void protobuf_AssignDescriptors() {
AddDescriptors();
::google::protobuf::MessageFactory* factory = NULL;
AssignDescriptors(
"google/protobuf/any.proto", schemas, file_default_instances, TableStruct::offsets, factory,
file_level_metadata, NULL, NULL);
}
void protobuf_AssignDescriptorsOnce() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors);
}
void protobuf_RegisterTypes(const ::std::string&) GOOGLE_PROTOBUF_ATTRIBUTE_COLD;
void protobuf_RegisterTypes(const ::std::string&) {
protobuf_AssignDescriptorsOnce();
::google::protobuf::internal::RegisterAllTypes(file_level_metadata, 1);
}
void AddDescriptorsImpl() {
InitDefaults();
static const char descriptor[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
"\n\031google/protobuf/any.proto\022\017google.prot"
"obuf\"&\n\003Any\022\020\n\010type_url\030\001 \001(\t\022\r\n\005value\030\002"
" \001(\014Bo\n\023com.google.protobufB\010AnyProtoP\001Z"
"%github.com/golang/protobuf/ptypes/any\242\002"
"\003GPB\252\002\036Google.Protobuf.WellKnownTypesb\006p"
"roto3"
};
::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
descriptor, 205);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"google/protobuf/any.proto", &protobuf_RegisterTypes);
}
void AddDescriptors() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);
}
// Force AddDescriptors() to be called at dynamic initialization time.
struct StaticDescriptorInitializer {
StaticDescriptorInitializer() {
AddDescriptors();
}
} static_descriptor_initializer;
} // namespace protobuf_google_2fprotobuf_2fany_2eproto
namespace google {
namespace protobuf {
// ===================================================================
void Any::InitAsDefaultInstance() {
}
void Any::PackFrom(const ::google::protobuf::Message& message) {
_any_metadata_.PackFrom(message);
}
void Any::PackFrom(const ::google::protobuf::Message& message,
const ::std::string& type_url_prefix) {
_any_metadata_.PackFrom(message, type_url_prefix);
}
bool Any::UnpackTo(::google::protobuf::Message* message) const {
return _any_metadata_.UnpackTo(message);
}
#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Any::kTypeUrlFieldNumber;
const int Any::kValueFieldNumber;
#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Any::Any()
: ::google::protobuf::Message(), _internal_metadata_(NULL), _any_metadata_(&type_url_, &value_) {
if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
::protobuf_google_2fprotobuf_2fany_2eproto::InitDefaultsAny();
}
SharedCtor();
// @@protoc_insertion_point(constructor:google.protobuf.Any)
}
Any::Any(const Any& from)
: ::google::protobuf::Message(),
_internal_metadata_(NULL),
_cached_size_(0),
_any_metadata_(&type_url_, &value_) {
_internal_metadata_.MergeFrom(from._internal_metadata_);
type_url_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (from.type_url().size() > 0) {
type_url_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.type_url_);
}
value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
if (from.value().size() > 0) {
value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.value_);
}
// @@protoc_insertion_point(copy_constructor:google.protobuf.Any)
}
void Any::SharedCtor() {
type_url_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
value_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
_cached_size_ = 0;
}
Any::~Any() {
// @@protoc_insertion_point(destructor:google.protobuf.Any)
SharedDtor();
}
void Any::SharedDtor() {
type_url_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
void Any::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
}
const ::google::protobuf::Descriptor* Any::descriptor() {
::protobuf_google_2fprotobuf_2fany_2eproto::protobuf_AssignDescriptorsOnce();
return ::protobuf_google_2fprotobuf_2fany_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
}
const Any& Any::default_instance() {
::protobuf_google_2fprotobuf_2fany_2eproto::InitDefaultsAny();
return *internal_default_instance();
}
Any* Any::New(::google::protobuf::Arena* arena) const {
Any* n = new Any;
if (arena != NULL) {
arena->Own(n);
}
return n;
}
void Any::Clear() {
// @@protoc_insertion_point(message_clear_start:google.protobuf.Any)
::google::protobuf::uint32 cached_has_bits = 0;
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
_internal_metadata_.Clear();
}
bool Any::MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) {
#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
// @@protoc_insertion_point(parse_start:google.protobuf.Any)
for (;;) {
::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
tag = p.first;
if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// string type_url = 1;
case 1: {
if (static_cast< ::google::protobuf::uint8>(tag) ==
static_cast< ::google::protobuf::uint8>(10u /* 10 & 0xFF */)) {
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_type_url()));
DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
this->type_url().data(), static_cast<int>(this->type_url().length()),
::google::protobuf::internal::WireFormatLite::PARSE,
"google.protobuf.Any.type_url"));
} else {
goto handle_unusual;
}
break;
}
// bytes value = 2;
case 2: {
if (static_cast< ::google::protobuf::uint8>(tag) ==
static_cast< ::google::protobuf::uint8>(18u /* 18 & 0xFF */)) {
DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
input, this->mutable_value()));
} else {
goto handle_unusual;
}
break;
}
default: {
handle_unusual:
if (tag == 0) {
goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, _internal_metadata_.mutable_unknown_fields()));
break;
}
}
}
success:
// @@protoc_insertion_point(parse_success:google.protobuf.Any)
return true;
failure:
// @@protoc_insertion_point(parse_failure:google.protobuf.Any)
return false;
#undef DO_
}
void Any::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
// @@protoc_insertion_point(serialize_start:google.protobuf.Any)
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
// string type_url = 1;
if (this->type_url().size() > 0) {
::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
this->type_url().data(), static_cast<int>(this->type_url().length()),
::google::protobuf::internal::WireFormatLite::SERIALIZE,
"google.protobuf.Any.type_url");
::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
1, this->type_url(), output);
}
// bytes value = 2;
if (this->value().size() > 0) {
::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
2, this->value(), output);
}
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), output);
}
// @@protoc_insertion_point(serialize_end:google.protobuf.Any)
}
::google::protobuf::uint8* Any::InternalSerializeWithCachedSizesToArray(
bool deterministic, ::google::protobuf::uint8* target) const {
(void)deterministic; // Unused
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Any)
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
// string type_url = 1;
if (this->type_url().size() > 0) {
::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
this->type_url().data(), static_cast<int>(this->type_url().length()),
::google::protobuf::internal::WireFormatLite::SERIALIZE,
"google.protobuf.Any.type_url");
target =
::google::protobuf::internal::WireFormatLite::WriteStringToArray(
1, this->type_url(), target);
}
// bytes value = 2;
if (this->value().size() > 0) {
target =
::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
2, this->value(), target);
}
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), target);
}
// @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Any)
return target;
}
size_t Any::ByteSizeLong() const {
// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Any)
size_t total_size = 0;
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()));
}
// string type_url = 1;
if (this->type_url().size() > 0) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->type_url());
}
// bytes value = 2;
if (this->value().size() > 0) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::BytesSize(
this->value());
}
int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = cached_size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
return total_size;
}
void Any::MergeFrom(const ::google::protobuf::Message& from) {
// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Any)
GOOGLE_DCHECK_NE(&from, this);
const Any* source =
::google::protobuf::internal::DynamicCastToGenerated<const Any>(
&from);
if (source == NULL) {
// @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Any)
::google::protobuf::internal::ReflectionOps::Merge(from, this);
} else {
// @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Any)
MergeFrom(*source);
}
}
void Any::MergeFrom(const Any& from) {
// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Any)
GOOGLE_DCHECK_NE(&from, this);
_internal_metadata_.MergeFrom(from._internal_metadata_);
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
if (from.type_url().size() > 0) {
type_url_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.type_url_);
}
if (from.value().size() > 0) {
value_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.value_);
}
}
void Any::CopyFrom(const ::google::protobuf::Message& from) {
// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Any)
if (&from == this) return;
Clear();
MergeFrom(from);
}
void Any::CopyFrom(const Any& from) {
// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Any)
if (&from == this) return;
Clear();
MergeFrom(from);
}
bool Any::IsInitialized() const {
return true;
}
void Any::Swap(Any* other) {
if (other == this) return;
InternalSwap(other);
}
void Any::InternalSwap(Any* other) {
using std::swap;
type_url_.Swap(&other->type_url_);
value_.Swap(&other->value_);
_internal_metadata_.Swap(&other->_internal_metadata_);
swap(_cached_size_, other->_cached_size_);
}
::google::protobuf::Metadata Any::GetMetadata() const {
protobuf_google_2fprotobuf_2fany_2eproto::protobuf_AssignDescriptorsOnce();
return ::protobuf_google_2fprotobuf_2fany_2eproto::file_level_metadata[kIndexInFileMessages];
}
// @@protoc_insertion_point(namespace_scope)
} // namespace protobuf
} // namespace google
// @@protoc_insertion_point(global_scope)
+323
View File
@@ -0,0 +1,323 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/protobuf/any.proto
#ifndef PROTOBUF_google_2fprotobuf_2fany_2eproto__INCLUDED
#define PROTOBUF_google_2fprotobuf_2fany_2eproto__INCLUDED
#include <string>
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3005000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3005001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
#endif
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/metadata.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h> // IWYU pragma: export
#include <google/protobuf/extension_set.h> // IWYU pragma: export
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/any.h>
// @@protoc_insertion_point(includes)
namespace protobuf_google_2fprotobuf_2fany_2eproto {
// Internal implementation detail -- do not use these members.
struct LIBPROTOBUF_EXPORT TableStruct {
static const ::google::protobuf::internal::ParseTableField entries[];
static const ::google::protobuf::internal::AuxillaryParseTableField aux[];
static const ::google::protobuf::internal::ParseTable schema[1];
static const ::google::protobuf::internal::FieldMetadata field_metadata[];
static const ::google::protobuf::internal::SerializationTable serialization_table[];
static const ::google::protobuf::uint32 offsets[];
};
void LIBPROTOBUF_EXPORT AddDescriptors();
void LIBPROTOBUF_EXPORT InitDefaultsAnyImpl();
void LIBPROTOBUF_EXPORT InitDefaultsAny();
inline void LIBPROTOBUF_EXPORT InitDefaults() {
InitDefaultsAny();
}
} // namespace protobuf_google_2fprotobuf_2fany_2eproto
namespace google {
namespace protobuf {
class Any;
class AnyDefaultTypeInternal;
LIBPROTOBUF_EXPORT extern AnyDefaultTypeInternal _Any_default_instance_;
} // namespace protobuf
} // namespace google
namespace google {
namespace protobuf {
// ===================================================================
class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Any) */ {
public:
Any();
virtual ~Any();
Any(const Any& from);
inline Any& operator=(const Any& from) {
CopyFrom(from);
return *this;
}
#if LANG_CXX11
Any(Any&& from) noexcept
: Any() {
*this = ::std::move(from);
}
inline Any& operator=(Any&& from) noexcept {
if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
if (this != &from) InternalSwap(&from);
} else {
CopyFrom(from);
}
return *this;
}
#endif
static const ::google::protobuf::Descriptor* descriptor();
static const Any& default_instance();
static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY
static inline const Any* internal_default_instance() {
return reinterpret_cast<const Any*>(
&_Any_default_instance_);
}
static PROTOBUF_CONSTEXPR int const kIndexInFileMessages =
0;
// implements Any -----------------------------------------------
void PackFrom(const ::google::protobuf::Message& message);
void PackFrom(const ::google::protobuf::Message& message,
const ::std::string& type_url_prefix);
bool UnpackTo(::google::protobuf::Message* message) const;
template<typename T> bool Is() const {
return _any_metadata_.Is<T>();
}
void Swap(Any* other);
friend void swap(Any& a, Any& b) {
a.Swap(&b);
}
// implements Message ----------------------------------------------
inline Any* New() const PROTOBUF_FINAL { return New(NULL); }
Any* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
void CopyFrom(const Any& from);
void MergeFrom(const Any& from);
void Clear() PROTOBUF_FINAL;
bool IsInitialized() const PROTOBUF_FINAL;
size_t ByteSizeLong() const PROTOBUF_FINAL;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
private:
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const PROTOBUF_FINAL;
void InternalSwap(Any* other);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return NULL;
}
inline void* MaybeArenaPtr() const {
return NULL;
}
public:
::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
// nested types ----------------------------------------------------
// accessors -------------------------------------------------------
// string type_url = 1;
void clear_type_url();
static const int kTypeUrlFieldNumber = 1;
const ::std::string& type_url() const;
void set_type_url(const ::std::string& value);
#if LANG_CXX11
void set_type_url(::std::string&& value);
#endif
void set_type_url(const char* value);
void set_type_url(const char* value, size_t size);
::std::string* mutable_type_url();
::std::string* release_type_url();
void set_allocated_type_url(::std::string* type_url);
// bytes value = 2;
void clear_value();
static const int kValueFieldNumber = 2;
const ::std::string& value() const;
void set_value(const ::std::string& value);
#if LANG_CXX11
void set_value(::std::string&& value);
#endif
void set_value(const char* value);
void set_value(const void* value, size_t size);
::std::string* mutable_value();
::std::string* release_value();
void set_allocated_value(::std::string* value);
// @@protoc_insertion_point(class_scope:google.protobuf.Any)
private:
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
::google::protobuf::internal::ArenaStringPtr type_url_;
::google::protobuf::internal::ArenaStringPtr value_;
mutable int _cached_size_;
::google::protobuf::internal::AnyMetadata _any_metadata_;
friend struct ::protobuf_google_2fprotobuf_2fany_2eproto::TableStruct;
friend void ::protobuf_google_2fprotobuf_2fany_2eproto::InitDefaultsAnyImpl();
};
// ===================================================================
// ===================================================================
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif // __GNUC__
// Any
// string type_url = 1;
inline void Any::clear_type_url() {
type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline const ::std::string& Any::type_url() const {
// @@protoc_insertion_point(field_get:google.protobuf.Any.type_url)
return type_url_.GetNoArena();
}
inline void Any::set_type_url(const ::std::string& value) {
type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
// @@protoc_insertion_point(field_set:google.protobuf.Any.type_url)
}
#if LANG_CXX11
inline void Any::set_type_url(::std::string&& value) {
type_url_.SetNoArena(
&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value));
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.Any.type_url)
}
#endif
inline void Any::set_type_url(const char* value) {
GOOGLE_DCHECK(value != NULL);
type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
// @@protoc_insertion_point(field_set_char:google.protobuf.Any.type_url)
}
inline void Any::set_type_url(const char* value, size_t size) {
type_url_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
::std::string(reinterpret_cast<const char*>(value), size));
// @@protoc_insertion_point(field_set_pointer:google.protobuf.Any.type_url)
}
inline ::std::string* Any::mutable_type_url() {
// @@protoc_insertion_point(field_mutable:google.protobuf.Any.type_url)
return type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* Any::release_type_url() {
// @@protoc_insertion_point(field_release:google.protobuf.Any.type_url)
return type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void Any::set_allocated_type_url(::std::string* type_url) {
if (type_url != NULL) {
} else {
}
type_url_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type_url);
// @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.type_url)
}
// bytes value = 2;
inline void Any::clear_value() {
value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline const ::std::string& Any::value() const {
// @@protoc_insertion_point(field_get:google.protobuf.Any.value)
return value_.GetNoArena();
}
inline void Any::set_value(const ::std::string& value) {
value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
// @@protoc_insertion_point(field_set:google.protobuf.Any.value)
}
#if LANG_CXX11
inline void Any::set_value(::std::string&& value) {
value_.SetNoArena(
&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value));
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.Any.value)
}
#endif
inline void Any::set_value(const char* value) {
GOOGLE_DCHECK(value != NULL);
value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
// @@protoc_insertion_point(field_set_char:google.protobuf.Any.value)
}
inline void Any::set_value(const void* value, size_t size) {
value_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
::std::string(reinterpret_cast<const char*>(value), size));
// @@protoc_insertion_point(field_set_pointer:google.protobuf.Any.value)
}
inline ::std::string* Any::mutable_value() {
// @@protoc_insertion_point(field_mutable:google.protobuf.Any.value)
return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline ::std::string* Any::release_value() {
// @@protoc_insertion_point(field_release:google.protobuf.Any.value)
return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
}
inline void Any::set_allocated_value(::std::string* value) {
if (value != NULL) {
} else {
}
value_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
// @@protoc_insertion_point(field_set_allocated:google.protobuf.Any.value)
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif // __GNUC__
// @@protoc_insertion_point(namespace_scope)
} // namespace protobuf
} // namespace google
// @@protoc_insertion_point(global_scope)
#endif // PROTOBUF_google_2fprotobuf_2fany_2eproto__INCLUDED
-99
View File
@@ -1,99 +0,0 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <google/protobuf/any.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
namespace internal {
std::string GetTypeUrl(StringPiece message_name,
StringPiece type_url_prefix) {
if (!type_url_prefix.empty() &&
type_url_prefix[type_url_prefix.size() - 1] == '/') {
return StrCat(type_url_prefix, message_name);
} else {
return StrCat(type_url_prefix, "/", message_name);
}
}
const char kAnyFullTypeName[] = "google.protobuf.Any";
const char kTypeGoogleApisComPrefix[] = "type.googleapis.com/";
const char kTypeGoogleProdComPrefix[] = "type.googleprod.com/";
bool AnyMetadata::InternalPackFrom(Arena* arena, const MessageLite& message,
StringPiece type_url_prefix,
StringPiece type_name) {
type_url_->Set(&::google::protobuf::internal::GetEmptyString(),
GetTypeUrl(type_name, type_url_prefix), arena);
return message.SerializeToString(
value_->Mutable(ArenaStringPtr::EmptyDefault{}, arena));
}
bool AnyMetadata::InternalUnpackTo(StringPiece type_name,
MessageLite* message) const {
if (!InternalIs(type_name)) {
return false;
}
return message->ParseFromString(value_->Get());
}
bool AnyMetadata::InternalIs(StringPiece type_name) const {
StringPiece type_url = type_url_->Get();
return type_url.size() >= type_name.size() + 1 &&
type_url[type_url.size() - type_name.size() - 1] == '/' &&
HasSuffixString(type_url, type_name);
}
bool ParseAnyTypeUrl(StringPiece type_url, std::string* url_prefix,
std::string* full_type_name) {
size_t pos = type_url.find_last_of('/');
if (pos == std::string::npos || pos + 1 == type_url.size()) {
return false;
}
if (url_prefix) {
*url_prefix = std::string(type_url.substr(0, pos + 1));
}
*full_type_name = std::string(type_url.substr(pos + 1));
return true;
}
bool ParseAnyTypeUrl(StringPiece type_url, std::string* full_type_name) {
return ParseAnyTypeUrl(type_url, nullptr, full_type_name);
}
} // namespace internal
} // namespace protobuf
} // namespace google
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+282 -408
View File
@@ -31,481 +31,355 @@
#include <google/protobuf/arena.h>
#include <algorithm>
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <typeinfo>
#include <google/protobuf/arena_impl.h>
#include <google/protobuf/stubs/mutex.h>
#ifdef ADDRESS_SANITIZER
#include <sanitizer/asan_interface.h>
#endif // ADDRESS_SANITIZER
#include <google/protobuf/port_def.inc>
#include <google/protobuf/stubs/port.h>
namespace google {
static const size_t kMinCleanupListElements = 8;
static const size_t kMaxCleanupListElements = 64; // 1kB on 64-bit.
namespace protobuf {
namespace internal {
static SerialArena::Memory AllocateMemory(const AllocationPolicy* policy_ptr,
size_t last_size, size_t min_bytes) {
AllocationPolicy policy; // default policy
if (policy_ptr) policy = *policy_ptr;
size_t size;
if (last_size != 0) {
// Double the current block size, up to a limit.
auto max_size = policy.max_block_size;
size = std::min(2 * last_size, max_size);
} else {
size = policy.start_block_size;
}
// Verify that min_bytes + kBlockHeaderSize won't overflow.
GOOGLE_CHECK_LE(min_bytes,
std::numeric_limits<size_t>::max() - SerialArena::kBlockHeaderSize);
size = std::max(size, SerialArena::kBlockHeaderSize + min_bytes);
void* mem;
if (policy.block_alloc == nullptr) {
mem = ::operator new(size);
} else {
mem = policy.block_alloc(size);
}
return {mem, size};
}
class GetDeallocator {
public:
GetDeallocator(const AllocationPolicy* policy, size_t* space_allocated)
: dealloc_(policy ? policy->block_dealloc : nullptr),
space_allocated_(space_allocated) {}
void operator()(SerialArena::Memory mem) const {
#ifdef ADDRESS_SANITIZER
// This memory was provided by the underlying allocator as unpoisoned,
// so return it in an unpoisoned state.
ASAN_UNPOISON_MEMORY_REGION(mem.ptr, mem.size);
#endif // ADDRESS_SANITIZER
if (dealloc_) {
dealloc_(mem.ptr, mem.size);
} else {
#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
::operator delete(mem.ptr, mem.size);
#else
::operator delete(mem.ptr);
#endif
}
*space_allocated_ += mem.size;
}
private:
void (*dealloc_)(void*, size_t);
size_t* space_allocated_;
};
SerialArena::SerialArena(Block* b, void* owner) : space_allocated_(b->size) {
owner_ = owner;
head_ = b;
ptr_ = b->Pointer(kBlockHeaderSize + ThreadSafeArena::kSerialArenaSize);
limit_ = b->Pointer(b->size & static_cast<size_t>(-8));
}
SerialArena* SerialArena::New(Memory mem, void* owner) {
GOOGLE_DCHECK_LE(kBlockHeaderSize + ThreadSafeArena::kSerialArenaSize, mem.size);
auto b = new (mem.ptr) Block{nullptr, mem.size};
return new (b->Pointer(kBlockHeaderSize)) SerialArena(b, owner);
}
template <typename Deallocator>
SerialArena::Memory SerialArena::Free(Deallocator deallocator) {
Block* b = head_;
Memory mem = {b, b->size};
while (b->next) {
b = b->next; // We must first advance before deleting this block
deallocator(mem);
mem = {b, b->size};
}
return mem;
}
PROTOBUF_NOINLINE
std::pair<void*, SerialArena::CleanupNode*>
SerialArena::AllocateAlignedWithCleanupFallback(
size_t n, const AllocationPolicy* policy) {
AllocateNewBlock(n + kCleanupSize, policy);
return AllocateFromExistingWithCleanupFallback(n);
}
PROTOBUF_NOINLINE
void* SerialArena::AllocateAlignedFallback(size_t n,
const AllocationPolicy* policy) {
AllocateNewBlock(n, policy);
return AllocateFromExisting(n);
}
void SerialArena::AllocateNewBlock(size_t n, const AllocationPolicy* policy) {
// Sync limit to block
head_->start = reinterpret_cast<CleanupNode*>(limit_);
// Record how much used in this block.
space_used_ += ptr_ - head_->Pointer(kBlockHeaderSize);
auto mem = AllocateMemory(policy, head_->size, n);
// We don't want to emit an expensive RMW instruction that requires
// exclusive access to a cacheline. Hence we write it in terms of a
// regular add.
auto relaxed = std::memory_order_relaxed;
space_allocated_.store(space_allocated_.load(relaxed) + mem.size, relaxed);
head_ = new (mem.ptr) Block{head_, mem.size};
ptr_ = head_->Pointer(kBlockHeaderSize);
limit_ = head_->Pointer(head_->size);
#ifdef ADDRESS_SANITIZER
ASAN_POISON_MEMORY_REGION(ptr_, limit_ - ptr_);
#endif // ADDRESS_SANITIZER
}
uint64_t SerialArena::SpaceUsed() const {
uint64_t space_used = ptr_ - head_->Pointer(kBlockHeaderSize);
space_used += space_used_;
// Remove the overhead of the SerialArena itself.
space_used -= ThreadSafeArena::kSerialArenaSize;
return space_used;
}
void SerialArena::CleanupList() {
Block* b = head_;
b->start = reinterpret_cast<CleanupNode*>(limit_);
do {
auto* limit = reinterpret_cast<CleanupNode*>(
b->Pointer(b->size & static_cast<size_t>(-8)));
auto it = b->start;
auto num = limit - it;
if (num > 0) {
for (; it < limit; it++) {
it->cleanup(it->elem);
}
}
b = b->next;
} while (b);
}
ThreadSafeArena::CacheAlignedLifecycleIdGenerator
ThreadSafeArena::lifecycle_id_generator_;
google::protobuf::internal::SequenceNumber ArenaImpl::lifecycle_id_generator_;
#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
ThreadSafeArena::ThreadCache& ThreadSafeArena::thread_cache() {
ArenaImpl::ThreadCache& ArenaImpl::thread_cache() {
static internal::ThreadLocalStorage<ThreadCache>* thread_cache_ =
new internal::ThreadLocalStorage<ThreadCache>();
return *thread_cache_->Get();
}
#elif defined(PROTOBUF_USE_DLLS)
ThreadSafeArena::ThreadCache& ThreadSafeArena::thread_cache() {
static PROTOBUF_THREAD_LOCAL ThreadCache thread_cache_ = {
0, static_cast<LifecycleIdAtomic>(-1), nullptr};
ArenaImpl::ThreadCache& ArenaImpl::thread_cache() {
static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_ = { -1, NULL };
return thread_cache_;
}
#else
PROTOBUF_THREAD_LOCAL ThreadSafeArena::ThreadCache
ThreadSafeArena::thread_cache_ = {0, static_cast<LifecycleIdAtomic>(-1),
nullptr};
GOOGLE_THREAD_LOCAL ArenaImpl::ThreadCache ArenaImpl::thread_cache_ = {-1, NULL};
#endif
void ThreadSafeArena::InitializeFrom(void* mem, size_t size) {
GOOGLE_DCHECK_EQ(reinterpret_cast<uintptr_t>(mem) & 7, 0u);
GOOGLE_DCHECK(!AllocPolicy()); // Reset should call InitializeWithPolicy instead.
Init();
void ArenaImpl::Init() {
lifecycle_id_ = lifecycle_id_generator_.GetNext();
google::protobuf::internal::NoBarrier_Store(&hint_, 0);
google::protobuf::internal::NoBarrier_Store(&threads_, 0);
// Ignore initial block if it is too small.
if (mem != nullptr && size >= kBlockHeaderSize + kSerialArenaSize) {
alloc_policy_.set_is_user_owned_initial_block(true);
SetInitialBlock(mem, size);
}
}
void ThreadSafeArena::InitializeWithPolicy(void* mem, size_t size,
AllocationPolicy policy) {
#ifndef NDEBUG
const uint64_t old_alloc_policy = alloc_policy_.get_raw();
// If there was a policy (e.g., in Reset()), make sure flags were preserved.
#define GOOGLE_DCHECK_POLICY_FLAGS_() \
if (old_alloc_policy > 3) \
GOOGLE_CHECK_EQ(old_alloc_policy & 3, alloc_policy_.get_raw() & 3)
#else
#define GOOGLE_DCHECK_POLICY_FLAGS_()
#endif // NDEBUG
if (policy.IsDefault()) {
// Legacy code doesn't use the API above, but provides the initial block
// through ArenaOptions. I suspect most do not touch the allocation
// policy parameters.
InitializeFrom(mem, size);
GOOGLE_DCHECK_POLICY_FLAGS_();
return;
}
GOOGLE_DCHECK_EQ(reinterpret_cast<uintptr_t>(mem) & 7, 0u);
Init();
// Ignore initial block if it is too small. We include an optional
// AllocationPolicy in this check, so that this can be allocated on the
// first block.
constexpr size_t kAPSize = internal::AlignUpTo8(sizeof(AllocationPolicy));
constexpr size_t kMinimumSize = kBlockHeaderSize + kSerialArenaSize + kAPSize;
// The value for alloc_policy_ stores whether or not allocations should be
// recorded.
alloc_policy_.set_should_record_allocs(
policy.metrics_collector != nullptr &&
policy.metrics_collector->RecordAllocs());
// Make sure we have an initial block to store the AllocationPolicy.
if (mem != nullptr && size >= kMinimumSize) {
alloc_policy_.set_is_user_owned_initial_block(true);
if (initial_block_) {
// Thread which calls Init() owns the first block. This allows the
// single-threaded case to allocate on the first block without having to
// perform atomic operations.
InitBlock(initial_block_, &thread_cache(), options_.initial_block_size);
ThreadInfo* info = NewThreadInfo(initial_block_);
info->next = NULL;
google::protobuf::internal::NoBarrier_Store(&threads_,
reinterpret_cast<google::protobuf::internal::AtomicWord>(info));
google::protobuf::internal::NoBarrier_Store(&space_allocated_,
options_.initial_block_size);
CacheBlock(initial_block_);
} else {
auto tmp = AllocateMemory(&policy, 0, kMinimumSize);
mem = tmp.ptr;
size = tmp.size;
google::protobuf::internal::NoBarrier_Store(&space_allocated_, 0);
}
SetInitialBlock(mem, size);
auto sa = threads_.load(std::memory_order_relaxed);
// We ensured enough space so this cannot fail.
void* p;
if (!sa || !sa->MaybeAllocateAligned(kAPSize, &p)) {
GOOGLE_LOG(FATAL) << "MaybeAllocateAligned cannot fail here.";
return;
}
new (p) AllocationPolicy{policy};
// Low bits store flags, so they mustn't be overwritten.
GOOGLE_DCHECK_EQ(0, reinterpret_cast<uintptr_t>(p) & 3);
alloc_policy_.set_policy(reinterpret_cast<AllocationPolicy*>(p));
GOOGLE_DCHECK_POLICY_FLAGS_();
#undef GOOGLE_DCHECK_POLICY_FLAGS_
}
void ThreadSafeArena::Init() {
#ifndef NDEBUG
const bool was_message_owned = IsMessageOwned();
#endif // NDEBUG
ThreadCache& tc = thread_cache();
auto id = tc.next_lifecycle_id;
// We increment lifecycle_id's by multiples of two so we can use bit 0 as
// a tag.
constexpr uint64_t kDelta = 2;
constexpr uint64_t kInc = ThreadCache::kPerThreadIds * kDelta;
if (PROTOBUF_PREDICT_FALSE((id & (kInc - 1)) == 0)) {
constexpr auto relaxed = std::memory_order_relaxed;
// On platforms that don't support uint64_t atomics we can certainly not
// afford to increment by large intervals and expect uniqueness due to
// wrapping, hence we only add by 1.
id = lifecycle_id_generator_.id.fetch_add(1, relaxed) * kInc;
}
tc.next_lifecycle_id = id + kDelta;
// Message ownership is stored in tag_and_id_, and is set in the constructor.
// This flag bit must be preserved, even across calls to Reset().
tag_and_id_ = id | (tag_and_id_ & kMessageOwnedArena);
hint_.store(nullptr, std::memory_order_relaxed);
threads_.store(nullptr, std::memory_order_relaxed);
#ifndef NDEBUG
GOOGLE_CHECK_EQ(was_message_owned, IsMessageOwned());
#endif // NDEBUG
}
void ThreadSafeArena::SetInitialBlock(void* mem, size_t size) {
SerialArena* serial = SerialArena::New({mem, size}, &thread_cache());
serial->set_next(NULL);
threads_.store(serial, std::memory_order_relaxed);
CacheSerialArena(serial);
}
ThreadSafeArena::~ThreadSafeArena() {
ArenaImpl::~ArenaImpl() {
// Have to do this in a first pass, because some of the destructors might
// refer to memory in other blocks.
CleanupList();
size_t space_allocated = 0;
auto mem = Free(&space_allocated);
// Policy is about to get deleted.
auto* p = alloc_policy_.get();
ArenaMetricsCollector* collector = p ? p->metrics_collector : nullptr;
if (alloc_policy_.is_user_owned_initial_block()) {
space_allocated += mem.size;
} else {
GetDeallocator(alloc_policy_.get(), &space_allocated)(mem);
}
if (collector) collector->OnDestroy(space_allocated);
FreeBlocks();
}
SerialArena::Memory ThreadSafeArena::Free(size_t* space_allocated) {
SerialArena::Memory mem = {nullptr, 0};
auto deallocator = GetDeallocator(alloc_policy_.get(), space_allocated);
PerSerialArena([deallocator, &mem](SerialArena* a) {
if (mem.ptr) deallocator(mem);
mem = a->Free(deallocator);
});
uint64 ArenaImpl::Reset() {
// Have to do this in a first pass, because some of the destructors might
// refer to memory in other blocks.
CleanupList();
uint64 space_allocated = FreeBlocks();
Init();
return space_allocated;
}
ArenaImpl::Block* ArenaImpl::NewBlock(void* me, Block* my_last_block,
size_t min_bytes) {
size_t size;
if (my_last_block != NULL) {
// Double the current block size, up to a limit.
size = std::min(2 * my_last_block->size, options_.max_block_size);
} else {
size = options_.start_block_size;
}
// Verify that min_bytes + kHeaderSize won't overflow.
GOOGLE_CHECK_LE(min_bytes, std::numeric_limits<size_t>::max() - kHeaderSize);
size = std::max(size, kHeaderSize + min_bytes);
Block* b = reinterpret_cast<Block*>(options_.block_alloc(size));
InitBlock(b, me, size);
google::protobuf::internal::NoBarrier_AtomicIncrement(&space_allocated_, size);
return b;
}
void ArenaImpl::InitBlock(Block* b, void *me, size_t size) {
b->pos = kHeaderSize;
b->size = size;
b->owner = me;
b->next = NULL;
#ifdef ADDRESS_SANITIZER
// Poison the rest of the block for ASAN. It was unpoisoned by the underlying
// malloc but it's not yet usable until we return it as part of an allocation.
ASAN_POISON_MEMORY_REGION(
reinterpret_cast<char*>(b) + b->pos, b->size - b->pos);
#endif // ADDRESS_SANITIZER
}
ArenaImpl::CleanupChunk* ArenaImpl::ExpandCleanupList(CleanupChunk* cleanup,
Block* b) {
size_t size = cleanup ? cleanup->size * 2 : kMinCleanupListElements;
size = std::min(size, kMaxCleanupListElements);
size_t bytes = internal::AlignUpTo8(CleanupChunk::SizeOf(size));
if (b->avail() < bytes) {
b = GetBlock(bytes);
}
CleanupChunk* list =
reinterpret_cast<CleanupChunk*>(AllocFromBlock(b, bytes));
list->next = b->thread_info->cleanup;
list->size = size;
list->len = 0;
b->thread_info->cleanup = list;
return list;
}
inline GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
void ArenaImpl::AddCleanupInBlock(
Block* b, void* elem, void (*func)(void*)) {
CleanupChunk* cleanup = b->thread_info->cleanup;
if (cleanup == NULL || cleanup->len == cleanup->size) {
cleanup = ExpandCleanupList(cleanup, b);
}
CleanupNode* node = &cleanup->nodes[cleanup->len++];
node->elem = elem;
node->cleanup = func;
}
void ArenaImpl::AddCleanup(void* elem, void (*cleanup)(void*)) {
return AddCleanupInBlock(GetBlock(0), elem, cleanup);
}
void* ArenaImpl::AllocateAligned(size_t n) {
GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n); // Must be already aligned.
return AllocFromBlock(GetBlock(n), n);
}
void* ArenaImpl::AllocateAlignedAndAddCleanup(size_t n,
void (*cleanup)(void*)) {
GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n); // Must be already aligned.
Block* b = GetBlock(n);
void* mem = AllocFromBlock(b, n);
AddCleanupInBlock(b, mem, cleanup);
return mem;
}
uint64_t ThreadSafeArena::Reset() {
// Have to do this in a first pass, because some of the destructors might
// refer to memory in other blocks.
CleanupList();
inline GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
ArenaImpl::Block* ArenaImpl::GetBlock(size_t n) {
Block* my_block = NULL;
// Discard all blocks except the special block (if present).
size_t space_allocated = 0;
auto mem = Free(&space_allocated);
// If this thread already owns a block in this arena then try to use that.
// This fast path optimizes the case where multiple threads allocate from the
// same arena.
ThreadCache* tc = &thread_cache();
if (tc->last_lifecycle_id_seen == lifecycle_id_) {
my_block = tc->last_block_used_;
if (my_block->avail() >= n) {
return my_block;
}
}
AllocationPolicy* policy = alloc_policy_.get();
if (policy) {
auto saved_policy = *policy;
if (alloc_policy_.is_user_owned_initial_block()) {
space_allocated += mem.size;
} else {
GetDeallocator(alloc_policy_.get(), &space_allocated)(mem);
mem.ptr = nullptr;
mem.size = 0;
// Check whether we own the last accessed block on this arena.
// This fast path optimizes the case where a single thread uses multiple
// arenas.
Block* b = reinterpret_cast<Block*>(google::protobuf::internal::Acquire_Load(&hint_));
if (b != NULL && b->owner == tc) {
my_block = b;
if (my_block->avail() >= n) {
return my_block;
}
ArenaMetricsCollector* collector = saved_policy.metrics_collector;
if (collector) collector->OnReset(space_allocated);
InitializeWithPolicy(mem.ptr, mem.size, saved_policy);
} else {
GOOGLE_DCHECK(!alloc_policy_.should_record_allocs());
// Nullptr policy
if (alloc_policy_.is_user_owned_initial_block()) {
space_allocated += mem.size;
InitializeFrom(mem.ptr, mem.size);
} else {
GetDeallocator(alloc_policy_.get(), &space_allocated)(mem);
Init();
}
return GetBlockSlow(tc, my_block, n);
}
inline GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
void* ArenaImpl::AllocFromBlock(Block* b, size_t n) {
GOOGLE_DCHECK_EQ(internal::AlignUpTo8(b->pos), b->pos); // Must be already aligned.
GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n); // Must be already aligned.
GOOGLE_DCHECK_GE(b->avail(), n);
size_t p = b->pos;
b->pos = p + n;
#ifdef ADDRESS_SANITIZER
ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast<char*>(b) + p, n);
#endif // ADDRESS_SANITIZER
return reinterpret_cast<char*>(b) + p;
}
ArenaImpl::Block* ArenaImpl::GetBlockSlow(void* me, Block* my_full_block,
size_t n) {
ThreadInfo* info =
my_full_block ? my_full_block->thread_info : GetThreadInfo(me, n);
GOOGLE_DCHECK(info != NULL);
Block* b = info->head;
if (b->avail() < n) {
Block* new_b = NewBlock(me, b, n);
new_b->thread_info = info;
new_b->next = b;
info->head = new_b;
b = new_b;
}
CacheBlock(b);
return b;
}
uint64 ArenaImpl::SpaceAllocated() const {
return google::protobuf::internal::NoBarrier_Load(&space_allocated_);
}
uint64 ArenaImpl::SpaceUsed() const {
ThreadInfo* info =
reinterpret_cast<ThreadInfo*>(google::protobuf::internal::Acquire_Load(&threads_));
uint64 space_used = 0;
for ( ; info; info = info->next) {
// Remove the overhead of the ThreadInfo itself.
space_used -= sizeof(ThreadInfo);
for (Block* b = info->head; b; b = b->next) {
space_used += (b->pos - kHeaderSize);
}
}
return space_used;
}
uint64 ArenaImpl::FreeBlocks() {
uint64 space_allocated = 0;
// By omitting an Acquire barrier we ensure that any user code that doesn't
// properly synchronize Reset() or the destructor will throw a TSAN warning.
ThreadInfo* info =
reinterpret_cast<ThreadInfo*>(google::protobuf::internal::NoBarrier_Load(&threads_));
while (info) {
// This is inside the block we are freeing, so we need to read it now.
ThreadInfo* next_info = info->next;
for (Block* b = info->head; b; ) {
// This is inside the block we are freeing, so we need to read it now.
Block* next_block = b->next;
space_allocated += (b->size);
#ifdef ADDRESS_SANITIZER
// This memory was provided by the underlying allocator as unpoisoned, so
// return it in an unpoisoned state.
ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast<char*>(b), b->size);
#endif // ADDRESS_SANITIZER
if (b != initial_block_) {
options_.block_dealloc(b, b->size);
}
b = next_block;
}
info = next_info;
}
return space_allocated;
}
std::pair<void*, SerialArena::CleanupNode*>
ThreadSafeArena::AllocateAlignedWithCleanup(size_t n,
const std::type_info* type) {
SerialArena* arena;
if (PROTOBUF_PREDICT_TRUE(!alloc_policy_.should_record_allocs() &&
GetSerialArenaFast(&arena))) {
return arena->AllocateAlignedWithCleanup(n, alloc_policy_.get());
} else {
return AllocateAlignedWithCleanupFallback(n, type);
}
}
void ArenaImpl::CleanupList() {
// By omitting an Acquire barrier we ensure that any user code that doesn't
// properly synchronize Reset() or the destructor will throw a TSAN warning.
ThreadInfo* info =
reinterpret_cast<ThreadInfo*>(google::protobuf::internal::NoBarrier_Load(&threads_));
void ThreadSafeArena::AddCleanup(void* elem, void (*cleanup)(void*)) {
SerialArena* arena;
if (PROTOBUF_PREDICT_FALSE(!GetSerialArenaFast(&arena))) {
arena = GetSerialArenaFallback(&thread_cache());
}
arena->AddCleanup(elem, cleanup, AllocPolicy());
}
PROTOBUF_NOINLINE
void* ThreadSafeArena::AllocateAlignedFallback(size_t n,
const std::type_info* type) {
if (alloc_policy_.should_record_allocs()) {
alloc_policy_.RecordAlloc(type, n);
SerialArena* arena;
if (PROTOBUF_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
return arena->AllocateAligned(n, alloc_policy_.get());
for ( ; info; info = info->next) {
CleanupChunk* list = info->cleanup;
while (list) {
size_t n = list->len;
CleanupNode* node = &list->nodes[list->len - 1];
for (size_t i = 0; i < n; i++, node--) {
node->cleanup(node->elem);
}
list = list->next;
}
}
return GetSerialArenaFallback(&thread_cache())
->AllocateAligned(n, alloc_policy_.get());
}
PROTOBUF_NOINLINE
std::pair<void*, SerialArena::CleanupNode*>
ThreadSafeArena::AllocateAlignedWithCleanupFallback(
size_t n, const std::type_info* type) {
if (alloc_policy_.should_record_allocs()) {
alloc_policy_.RecordAlloc(type, n);
SerialArena* arena;
if (GetSerialArenaFast(&arena)) {
return arena->AllocateAlignedWithCleanup(n, alloc_policy_.get());
}
}
return GetSerialArenaFallback(&thread_cache())
->AllocateAlignedWithCleanup(n, alloc_policy_.get());
ArenaImpl::ThreadInfo* ArenaImpl::NewThreadInfo(Block* b) {
GOOGLE_DCHECK(FindThreadInfo(b->owner) == NULL);
ThreadInfo* info =
reinterpret_cast<ThreadInfo*>(AllocFromBlock(b, sizeof(ThreadInfo)));
b->thread_info = info;
info->owner = b->owner;
info->head = b;
info->cleanup = NULL;
return info;
}
uint64_t ThreadSafeArena::SpaceAllocated() const {
SerialArena* serial = threads_.load(std::memory_order_acquire);
uint64_t res = 0;
for (; serial; serial = serial->next()) {
res += serial->SpaceAllocated();
}
return res;
}
uint64_t ThreadSafeArena::SpaceUsed() const {
SerialArena* serial = threads_.load(std::memory_order_acquire);
uint64_t space_used = 0;
for (; serial; serial = serial->next()) {
space_used += serial->SpaceUsed();
}
return space_used - (alloc_policy_.get() ? sizeof(AllocationPolicy) : 0);
}
void ThreadSafeArena::CleanupList() {
PerSerialArena([](SerialArena* a) { a->CleanupList(); });
}
PROTOBUF_NOINLINE
SerialArena* ThreadSafeArena::GetSerialArenaFallback(void* me) {
// Look for this SerialArena in our linked list.
SerialArena* serial = threads_.load(std::memory_order_acquire);
for (; serial; serial = serial->next()) {
if (serial->owner() == me) {
break;
ArenaImpl::ThreadInfo* ArenaImpl::FindThreadInfo(void* me) {
ThreadInfo* info =
reinterpret_cast<ThreadInfo*>(google::protobuf::internal::Acquire_Load(&threads_));
for ( ; info; info = info->next) {
if (info->owner == me) {
return info;
}
}
if (!serial) {
// This thread doesn't have any SerialArena, which also means it doesn't
// have any blocks yet. So we'll allocate its first block now.
serial = SerialArena::New(
AllocateMemory(alloc_policy_.get(), 0, kSerialArenaSize), me);
return NULL;
}
SerialArena* head = threads_.load(std::memory_order_relaxed);
ArenaImpl::ThreadInfo* ArenaImpl::GetThreadInfo(void* me, size_t n) {
ThreadInfo* info = FindThreadInfo(me);
if (!info) {
// This thread doesn't have any ThreadInfo, which also means it doesn't have
// any blocks yet. So we'll allocate its first block now.
Block* b = NewBlock(me, NULL, sizeof(ThreadInfo) + n);
info = NewThreadInfo(b);
google::protobuf::internal::AtomicWord head;
do {
serial->set_next(head);
} while (!threads_.compare_exchange_weak(
head, serial, std::memory_order_release, std::memory_order_relaxed));
head = google::protobuf::internal::NoBarrier_Load(&threads_);
info->next = reinterpret_cast<ThreadInfo*>(head);
} while (google::protobuf::internal::Release_CompareAndSwap(
&threads_, head, reinterpret_cast<google::protobuf::internal::AtomicWord>(info)) != head);
}
CacheSerialArena(serial);
return serial;
return info;
}
} // namespace internal
PROTOBUF_FUNC_ALIGN(32)
void* Arena::AllocateAlignedNoHook(size_t n) {
return impl_.AllocateAligned(n, nullptr);
void Arena::CallDestructorHooks() {
uint64 space_allocated = impl_.SpaceAllocated();
// Call the reset hook
if (on_arena_reset_ != NULL) {
on_arena_reset_(this, hooks_cookie_, space_allocated);
}
// Call the destruction hook
if (on_arena_destruction_ != NULL) {
on_arena_destruction_(this, hooks_cookie_, space_allocated);
}
}
PROTOBUF_FUNC_ALIGN(32)
void* Arena::AllocateAlignedWithHook(size_t n, const std::type_info* type) {
return impl_.AllocateAligned(n, type);
}
PROTOBUF_FUNC_ALIGN(32)
std::pair<void*, internal::SerialArena::CleanupNode*>
Arena::AllocateAlignedWithCleanup(size_t n, const std::type_info* type) {
return impl_.AllocateAlignedWithCleanup(n, type);
void Arena::OnArenaAllocation(const std::type_info* allocated_type,
size_t n) const {
if (on_arena_allocation_ != NULL) {
on_arena_allocation_(allocated_type, n, hooks_cookie_);
}
}
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
File diff suppressed because it is too large Load Diff
+137 -457
View File
@@ -33,530 +33,210 @@
#ifndef GOOGLE_PROTOBUF_ARENA_IMPL_H__
#define GOOGLE_PROTOBUF_ARENA_IMPL_H__
#include <atomic>
#include <limits>
#include <typeinfo>
#include <google/protobuf/stubs/atomic_sequence_num.h>
#include <google/protobuf/stubs/atomicops.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/mutex.h>
#include <google/protobuf/stubs/type_traits.h>
#ifdef ADDRESS_SANITIZER
#include <sanitizer/asan_interface.h>
#endif // ADDRESS_SANITIZER
#include <google/protobuf/port_def.inc>
#include <google/protobuf/stubs/port.h>
namespace google {
namespace protobuf {
namespace internal {
inline constexpr size_t AlignUpTo8(size_t n) {
inline size_t AlignUpTo8(size_t n) {
// Align n to next multiple of 8 (from Hacker's Delight, Chapter 3.)
return (n + 7) & static_cast<size_t>(-8);
return (n + 7) & -8;
}
using LifecycleIdAtomic = uint64_t;
// MetricsCollector collects stats for a particular arena.
class PROTOBUF_EXPORT ArenaMetricsCollector {
public:
ArenaMetricsCollector(bool record_allocs) : record_allocs_(record_allocs) {}
// Invoked when the arena is about to be destroyed. This method will
// typically finalize any metric collection and delete the collector.
// space_allocated is the space used by the arena.
virtual void OnDestroy(uint64_t space_allocated) = 0;
// OnReset() is called when the associated arena is reset.
// space_allocated is the space used by the arena just before the reset.
virtual void OnReset(uint64_t space_allocated) = 0;
// OnAlloc is called when an allocation happens.
// type_info is promised to be static - its lifetime extends to
// match program's lifetime (It is given by typeid operator).
// Note: typeid(void) will be passed as allocated_type every time we
// intentionally want to avoid monitoring an allocation. (i.e. internal
// allocations for managing the arena)
virtual void OnAlloc(const std::type_info* allocated_type,
uint64_t alloc_size) = 0;
// Does OnAlloc() need to be called? If false, metric collection overhead
// will be reduced since we will not do extra work per allocation.
bool RecordAllocs() { return record_allocs_; }
protected:
// This class is destructed by the call to OnDestroy().
~ArenaMetricsCollector() = default;
const bool record_allocs_;
};
struct AllocationPolicy {
static constexpr size_t kDefaultStartBlockSize = 256;
static constexpr size_t kDefaultMaxBlockSize = 8192;
size_t start_block_size = kDefaultStartBlockSize;
size_t max_block_size = kDefaultMaxBlockSize;
void* (*block_alloc)(size_t) = nullptr;
void (*block_dealloc)(void*, size_t) = nullptr;
ArenaMetricsCollector* metrics_collector = nullptr;
bool IsDefault() const {
return start_block_size == kDefaultMaxBlockSize &&
max_block_size == kDefaultMaxBlockSize && block_alloc == nullptr &&
block_dealloc == nullptr && metrics_collector == nullptr;
}
};
// Tagged pointer to an AllocationPolicy.
class TaggedAllocationPolicyPtr {
public:
constexpr TaggedAllocationPolicyPtr() : policy_(0) {}
explicit TaggedAllocationPolicyPtr(AllocationPolicy* policy)
: policy_(reinterpret_cast<uintptr_t>(policy)) {}
void set_policy(AllocationPolicy* policy) {
auto bits = policy_ & kTagsMask;
policy_ = reinterpret_cast<uintptr_t>(policy) | bits;
}
AllocationPolicy* get() {
return reinterpret_cast<AllocationPolicy*>(policy_ & kPtrMask);
}
const AllocationPolicy* get() const {
return reinterpret_cast<const AllocationPolicy*>(policy_ & kPtrMask);
}
AllocationPolicy& operator*() { return *get(); }
const AllocationPolicy& operator*() const { return *get(); }
AllocationPolicy* operator->() { return get(); }
const AllocationPolicy* operator->() const { return get(); }
bool is_user_owned_initial_block() const {
return static_cast<bool>(get_mask<kUserOwnedInitialBlock>());
}
void set_is_user_owned_initial_block(bool v) {
set_mask<kUserOwnedInitialBlock>(v);
}
bool should_record_allocs() const {
return static_cast<bool>(get_mask<kRecordAllocs>());
}
void set_should_record_allocs(bool v) { set_mask<kRecordAllocs>(v); }
uintptr_t get_raw() const { return policy_; }
inline void RecordAlloc(const std::type_info* allocated_type,
size_t n) const {
get()->metrics_collector->OnAlloc(allocated_type, n);
}
private:
enum : uintptr_t {
kUserOwnedInitialBlock = 1,
kRecordAllocs = 2,
};
static constexpr uintptr_t kTagsMask = 7;
static constexpr uintptr_t kPtrMask = ~kTagsMask;
template <uintptr_t kMask>
uintptr_t get_mask() const {
return policy_ & kMask;
}
template <uintptr_t kMask>
void set_mask(bool v) {
if (v) {
policy_ |= kMask;
} else {
policy_ &= ~kMask;
}
}
uintptr_t policy_;
};
// A simple arena allocator. Calls to allocate functions must be properly
// serialized by the caller, hence this class cannot be used as a general
// purpose allocator in a multi-threaded program. It serves as a building block
// for ThreadSafeArena, which provides a thread-safe arena allocator.
//
// This class manages
// 1) Arena bump allocation + owning memory blocks.
// 2) Maintaining a cleanup list.
// It delagetes the actual memory allocation back to ThreadSafeArena, which
// contains the information on block growth policy and backing memory allocation
// used.
class PROTOBUF_EXPORT SerialArena {
public:
struct Memory {
void* ptr;
size_t size;
};
// Node contains the ptr of the object to be cleaned up and the associated
// cleanup function ptr.
struct CleanupNode {
void* elem; // Pointer to the object to be cleaned up.
void (*cleanup)(void*); // Function pointer to the destructor or deleter.
};
void CleanupList();
uint64_t SpaceAllocated() const {
return space_allocated_.load(std::memory_order_relaxed);
}
uint64_t SpaceUsed() const;
bool HasSpace(size_t n) { return n <= static_cast<size_t>(limit_ - ptr_); }
void* AllocateAligned(size_t n, const AllocationPolicy* policy) {
GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n); // Must be already aligned.
GOOGLE_DCHECK_GE(limit_, ptr_);
if (PROTOBUF_PREDICT_FALSE(!HasSpace(n))) {
return AllocateAlignedFallback(n, policy);
}
return AllocateFromExisting(n);
}
private:
void* AllocateFromExisting(size_t n) {
void* ret = ptr_;
ptr_ += n;
#ifdef ADDRESS_SANITIZER
ASAN_UNPOISON_MEMORY_REGION(ret, n);
#endif // ADDRESS_SANITIZER
return ret;
}
public:
// Allocate space if the current region provides enough space.
bool MaybeAllocateAligned(size_t n, void** out) {
GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n); // Must be already aligned.
GOOGLE_DCHECK_GE(limit_, ptr_);
if (PROTOBUF_PREDICT_FALSE(!HasSpace(n))) return false;
*out = AllocateFromExisting(n);
return true;
}
std::pair<void*, CleanupNode*> AllocateAlignedWithCleanup(
size_t n, const AllocationPolicy* policy) {
GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n); // Must be already aligned.
if (PROTOBUF_PREDICT_FALSE(!HasSpace(n + kCleanupSize))) {
return AllocateAlignedWithCleanupFallback(n, policy);
}
return AllocateFromExistingWithCleanupFallback(n);
}
private:
std::pair<void*, CleanupNode*> AllocateFromExistingWithCleanupFallback(
size_t n) {
void* ret = ptr_;
ptr_ += n;
limit_ -= kCleanupSize;
#ifdef ADDRESS_SANITIZER
ASAN_UNPOISON_MEMORY_REGION(ret, n);
ASAN_UNPOISON_MEMORY_REGION(limit_, kCleanupSize);
#endif // ADDRESS_SANITIZER
return CreatePair(ret, reinterpret_cast<CleanupNode*>(limit_));
}
public:
void AddCleanup(void* elem, void (*cleanup)(void*),
const AllocationPolicy* policy) {
auto res = AllocateAlignedWithCleanup(0, policy);
res.second->elem = elem;
res.second->cleanup = cleanup;
}
void* owner() const { return owner_; }
SerialArena* next() const { return next_; }
void set_next(SerialArena* next) { next_ = next; }
private:
friend class ThreadSafeArena;
friend class ArenaBenchmark;
// Creates a new SerialArena inside mem using the remaining memory as for
// future allocations.
static SerialArena* New(SerialArena::Memory mem, void* owner);
// Free SerialArena returning the memory passed in to New
template <typename Deallocator>
Memory Free(Deallocator deallocator);
// Blocks are variable length malloc-ed objects. The following structure
// describes the common header for all blocks.
struct Block {
Block(Block* next, size_t size) : next(next), size(size), start(nullptr) {}
char* Pointer(size_t n) {
GOOGLE_DCHECK(n <= size);
return reinterpret_cast<char*>(this) + n;
}
Block* const next;
const size_t size;
CleanupNode* start;
// data follows
};
void* owner_; // &ThreadCache of this thread;
Block* head_; // Head of linked list of blocks.
SerialArena* next_; // Next SerialArena in this linked list.
size_t space_used_ = 0; // Necessary for metrics.
std::atomic<size_t> space_allocated_;
// Next pointer to allocate from. Always 8-byte aligned. Points inside
// head_ (and head_->pos will always be non-canonical). We keep these
// here to reduce indirection.
char* ptr_;
char* limit_;
// Constructor is private as only New() should be used.
inline SerialArena(Block* b, void* owner);
void* AllocateAlignedFallback(size_t n, const AllocationPolicy* policy);
std::pair<void*, CleanupNode*> AllocateAlignedWithCleanupFallback(
size_t n, const AllocationPolicy* policy);
void AllocateNewBlock(size_t n, const AllocationPolicy* policy);
std::pair<void*, CleanupNode*> CreatePair(void* ptr, CleanupNode* node) {
return {ptr, node};
}
public:
static constexpr size_t kBlockHeaderSize = AlignUpTo8(sizeof(Block));
static constexpr size_t kCleanupSize = AlignUpTo8(sizeof(CleanupNode));
};
// Tag type used to invoke the constructor of message-owned arena.
// Only message-owned arenas use this constructor for creation.
// Such constructors are internal implementation details of the library.
struct MessageOwned {
explicit MessageOwned() = default;
};
// This class provides the core Arena memory allocation library. Different
// implementations only need to implement the public interface below.
// Arena is not a template type as that would only be useful if all protos
// in turn would be templates, which will/cannot happen. However separating
// the memory allocation part from the cruft of the API users expect we can
// use #ifdef the select the best implementation based on hardware / OS.
class PROTOBUF_EXPORT ThreadSafeArena {
class LIBPROTOBUF_EXPORT ArenaImpl {
public:
ThreadSafeArena() { Init(); }
struct Options {
size_t start_block_size;
size_t max_block_size;
char* initial_block;
size_t initial_block_size;
void* (*block_alloc)(size_t);
void (*block_dealloc)(void*, size_t);
template <typename O>
explicit Options(const O& options)
: start_block_size(options.start_block_size),
max_block_size(options.max_block_size),
initial_block(options.initial_block),
initial_block_size(options.initial_block_size),
block_alloc(options.block_alloc),
block_dealloc(options.block_dealloc) {}
};
template <typename O>
explicit ArenaImpl(const O& options) : options_(options) {
if (options_.initial_block != NULL && options_.initial_block_size > 0) {
GOOGLE_CHECK_GE(options_.initial_block_size, sizeof(Block))
<< ": Initial block size too small for header.";
initial_block_ = reinterpret_cast<Block*>(options_.initial_block);
} else {
initial_block_ = NULL;
}
// Constructor solely used by message-owned arena.
ThreadSafeArena(internal::MessageOwned) : tag_and_id_(kMessageOwnedArena) {
Init();
}
ThreadSafeArena(char* mem, size_t size) { InitializeFrom(mem, size); }
explicit ThreadSafeArena(void* mem, size_t size,
const AllocationPolicy& policy) {
InitializeWithPolicy(mem, size, policy);
}
// Destructor deletes all owned heap allocated objects, and destructs objects
// that have non-trivial destructors, except for proto2 message objects whose
// destructors can be skipped. Also, frees all blocks except the initial block
// if it was passed in.
~ThreadSafeArena();
~ArenaImpl();
uint64_t Reset();
uint64 Reset();
uint64_t SpaceAllocated() const;
uint64_t SpaceUsed() const;
uint64 SpaceAllocated() const;
uint64 SpaceUsed() const;
void* AllocateAligned(size_t n, const std::type_info* type) {
SerialArena* arena;
if (PROTOBUF_PREDICT_TRUE(!alloc_policy_.should_record_allocs() &&
GetSerialArenaFast(&arena))) {
return arena->AllocateAligned(n, AllocPolicy());
} else {
return AllocateAlignedFallback(n, type);
}
}
void* AllocateAligned(size_t n);
// This function allocates n bytes if the common happy case is true and
// returns true. Otherwise does nothing and returns false. This strange
// semantics is necessary to allow callers to program functions that only
// have fallback function calls in tail position. This substantially improves
// code for the happy path.
PROTOBUF_NDEBUG_INLINE bool MaybeAllocateAligned(size_t n, void** out) {
SerialArena* a;
if (PROTOBUF_PREDICT_TRUE(!alloc_policy_.should_record_allocs() &&
GetSerialArenaFromThreadCache(&a))) {
return a->MaybeAllocateAligned(n, out);
}
return false;
}
std::pair<void*, SerialArena::CleanupNode*> AllocateAlignedWithCleanup(
size_t n, const std::type_info* type);
void* AllocateAlignedAndAddCleanup(size_t n, void (*cleanup)(void*));
// Add object pointer and cleanup function pointer to the list.
void AddCleanup(void* elem, void (*cleanup)(void*));
// Checks whether this arena is message-owned.
PROTOBUF_ALWAYS_INLINE bool IsMessageOwned() const {
return tag_and_id_ & kMessageOwnedArena;
}
private:
// Unique for each arena. Changes on Reset().
uint64_t tag_and_id_ = 0;
// The LSB of tag_and_id_ indicates if the arena is message-owned.
enum : uint64_t { kMessageOwnedArena = 1 };
// Node contains the ptr of the object to be cleaned up and the associated
// cleanup function ptr.
struct CleanupNode {
void* elem; // Pointer to the object to be cleaned up.
void (*cleanup)(void*); // Function pointer to the destructor or deleter.
};
TaggedAllocationPolicyPtr alloc_policy_; // Tagged pointer to AllocPolicy.
// Pointer to a linked list of SerialArena.
std::atomic<SerialArena*> threads_;
std::atomic<SerialArena*> hint_; // Fast thread-local block access
const AllocationPolicy* AllocPolicy() const { return alloc_policy_.get(); }
void InitializeFrom(void* mem, size_t size);
void InitializeWithPolicy(void* mem, size_t size, AllocationPolicy policy);
void* AllocateAlignedFallback(size_t n, const std::type_info* type);
std::pair<void*, SerialArena::CleanupNode*>
AllocateAlignedWithCleanupFallback(size_t n, const std::type_info* type);
void Init();
void SetInitialBlock(void* mem, size_t size);
// Delete or Destruct all objects owned by the arena.
void CleanupList();
inline uint64_t LifeCycleId() const {
return tag_and_id_ & ~kMessageOwnedArena;
}
inline void CacheSerialArena(SerialArena* serial) {
thread_cache().last_serial_arena = serial;
thread_cache().last_lifecycle_id_seen = tag_and_id_;
// TODO(haberman): evaluate whether we would gain efficiency by getting rid
// of hint_. It's the only write we do to ThreadSafeArena in the allocation
// path, which will dirty the cache line.
hint_.store(serial, std::memory_order_release);
}
PROTOBUF_NDEBUG_INLINE bool GetSerialArenaFast(SerialArena** arena) {
if (GetSerialArenaFromThreadCache(arena)) return true;
// Check whether we own the last accessed SerialArena on this arena. This
// fast path optimizes the case where a single thread uses multiple arenas.
ThreadCache* tc = &thread_cache();
SerialArena* serial = hint_.load(std::memory_order_acquire);
if (PROTOBUF_PREDICT_TRUE(serial != NULL && serial->owner() == tc)) {
*arena = serial;
return true;
// Cleanup uses a chunked linked list, to reduce pointer chasing.
struct CleanupChunk {
static size_t SizeOf(size_t i) {
return sizeof(CleanupChunk) + (sizeof(CleanupNode) * (i - 1));
}
return false;
}
size_t len; // Number of elements currently present.
size_t size; // Total elements in the list.
CleanupChunk* next; // Next node in the list.
CleanupNode nodes[1]; // True length is |size|.
};
PROTOBUF_NDEBUG_INLINE bool GetSerialArenaFromThreadCache(
SerialArena** arena) {
// If this thread already owns a block in this arena then try to use that.
// This fast path optimizes the case where multiple threads allocate from
// the same arena.
ThreadCache* tc = &thread_cache();
if (PROTOBUF_PREDICT_TRUE(tc->last_lifecycle_id_seen == tag_and_id_)) {
*arena = tc->last_serial_arena;
return true;
}
return false;
}
SerialArena* GetSerialArenaFallback(void* me);
struct Block;
template <typename Functor>
void PerSerialArena(Functor fn) {
// By omitting an Acquire barrier we ensure that any user code that doesn't
// properly synchronize Reset() or the destructor will throw a TSAN warning.
SerialArena* serial = threads_.load(std::memory_order_relaxed);
// Tracks per-thread info. ThreadInfos are kept in a linked list.
struct ThreadInfo {
void *owner; // &ThreadCache of this thread;
Block* head; // Head of linked list of blocks.
CleanupChunk* cleanup; // Head of cleanup list.
ThreadInfo* next; // Next ThreadInfo in this linked list.
};
for (; serial; serial = serial->next()) fn(serial);
}
// Blocks are variable length malloc-ed objects. The following structure
// describes the common header for all blocks.
struct Block {
void* owner; // &ThreadCache of thread that owns this block.
ThreadInfo* thread_info; // ThreadInfo of thread that owns this block.
Block* next; // Next block in arena (may have different owner)
// ((char*) &block) + pos is next available byte. It is always
// aligned at a multiple of 8 bytes.
size_t pos;
size_t size; // total size of the block.
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
size_t avail() const { return size - pos; }
// data follows
};
// Releases all memory except the first block which it returns. The first
// block might be owned by the user and thus need some extra checks before
// deleting.
SerialArena::Memory Free(size_t* space_allocated);
#ifdef _MSC_VER
#pragma warning(disable : 4324)
#endif
struct alignas(64) ThreadCache {
struct ThreadCache {
#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
// If we are using the ThreadLocalStorage class to store the ThreadCache,
// then the ThreadCache's default constructor has to be responsible for
// initializing it.
ThreadCache()
: next_lifecycle_id(0),
last_lifecycle_id_seen(-1),
last_serial_arena(NULL) {}
ThreadCache() : last_lifecycle_id_seen(-1), last_block_used_(NULL) {}
#endif
// Number of per-thread lifecycle IDs to reserve. Must be power of two.
// To reduce contention on a global atomic, each thread reserves a batch of
// IDs. The following number is calculated based on a stress test with
// ~6500 threads all frequently allocating a new arena.
static constexpr size_t kPerThreadIds = 256;
// Next lifecycle ID available to this thread. We need to reserve a new
// batch, if `next_lifecycle_id & (kPerThreadIds - 1) == 0`.
uint64_t next_lifecycle_id;
// The ThreadCache is considered valid as long as this matches the
// lifecycle_id of the arena being used.
uint64_t last_lifecycle_id_seen;
SerialArena* last_serial_arena;
int64 last_lifecycle_id_seen;
Block* last_block_used_;
};
// Lifecycle_id can be highly contended variable in a situation of lots of
// arena creation. Make sure that other global variables are not sharing the
// cacheline.
#ifdef _MSC_VER
#pragma warning(disable : 4324)
#endif
struct alignas(64) CacheAlignedLifecycleIdGenerator {
std::atomic<LifecycleIdAtomic> id;
};
static CacheAlignedLifecycleIdGenerator lifecycle_id_generator_;
static google::protobuf::internal::SequenceNumber lifecycle_id_generator_;
#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
// iOS does not support __thread keyword so we use a custom thread local
// storage class we implemented.
// Android ndk does not support GOOGLE_THREAD_LOCAL keyword so we use a custom thread
// local storage class we implemented.
// iOS also does not support the GOOGLE_THREAD_LOCAL keyword.
static ThreadCache& thread_cache();
#elif defined(PROTOBUF_USE_DLLS)
// Thread local variables cannot be exposed through DLL interface but we can
// wrap them in static functions.
static ThreadCache& thread_cache();
#else
static PROTOBUF_THREAD_LOCAL ThreadCache thread_cache_;
static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_;
static ThreadCache& thread_cache() { return thread_cache_; }
#endif
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ThreadSafeArena);
// All protos have pointers back to the arena hence Arena must have
// pointer stability.
ThreadSafeArena(ThreadSafeArena&&) = delete;
ThreadSafeArena& operator=(ThreadSafeArena&&) = delete;
void Init();
// Free all blocks and return the total space used which is the sums of sizes
// of the all the allocated blocks.
uint64 FreeBlocks();
void AddCleanupInBlock(Block* b, void* elem, void (*func)(void*));
CleanupChunk* ExpandCleanupList(CleanupChunk* cleanup, Block* b);
// Delete or Destruct all objects owned by the arena.
void CleanupList();
inline void CacheBlock(Block* block) {
thread_cache().last_block_used_ = block;
thread_cache().last_lifecycle_id_seen = lifecycle_id_;
// TODO(haberman): evaluate whether we would gain efficiency by getting rid
// of hint_. It's the only write we do to ArenaImpl in the allocation path,
// which will dirty the cache line.
google::protobuf::internal::Release_Store(&hint_, reinterpret_cast<google::protobuf::internal::AtomicWord>(block));
}
google::protobuf::internal::AtomicWord threads_; // Pointer to a linked list of ThreadInfo.
google::protobuf::internal::AtomicWord hint_; // Fast thread-local block access
google::protobuf::internal::AtomicWord space_allocated_; // Sum of sizes of all allocated blocks.
Block *initial_block_; // If non-NULL, points to the block that came from
// user data.
// Returns a block owned by this thread.
Block* GetBlock(size_t n);
Block* GetBlockSlow(void* me, Block* my_full_block, size_t n);
Block* NewBlock(void* me, Block* my_last_block, size_t min_bytes);
void InitBlock(Block* b, void *me, size_t size);
static void* AllocFromBlock(Block* b, size_t n);
ThreadInfo* NewThreadInfo(Block* b);
ThreadInfo* FindThreadInfo(void* me);
ThreadInfo* GetThreadInfo(void* me, size_t n);
int64 lifecycle_id_; // Unique for each arena. Changes on Reset().
Options options_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArenaImpl);
public:
// kBlockHeaderSize is sizeof(Block), aligned up to the nearest multiple of 8
// to protect the invariant that pos is always at a multiple of 8.
static constexpr size_t kBlockHeaderSize = SerialArena::kBlockHeaderSize;
static constexpr size_t kSerialArenaSize =
(sizeof(SerialArena) + 7) & static_cast<size_t>(-8);
static_assert(kBlockHeaderSize % 8 == 0,
"kBlockHeaderSize must be a multiple of 8.");
static_assert(kSerialArenaSize % 8 == 0,
"kSerialArenaSize must be a multiple of 8.");
// kHeaderSize is sizeof(Block), aligned up to the nearest multiple of 8 to
// protect the invariant that pos is always at a multiple of 8.
static const size_t kHeaderSize = (sizeof(Block) + 7) & -8;
#if LANG_CXX11
static_assert(kHeaderSize % 8 == 0, "kHeaderSize must be a multiple of 8.");
#endif
};
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_ARENA_IMPL_H__
+3 -246
View File
@@ -28,259 +28,16 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// The ArenaString implementation is not included in the open-source release. Do
// not include this file in the distribution.
#include <google/protobuf/arenastring.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/parse_context.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/stubs/mutex.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/stl_util.h>
// clang-format off
#include <google/protobuf/port_def.inc>
// clang-format on
namespace google {
namespace protobuf {
namespace internal {
const std::string& LazyString::Init() const {
static WrappedMutex mu{GOOGLE_PROTOBUF_LINKER_INITIALIZED};
mu.Lock();
const std::string* res = inited_.load(std::memory_order_acquire);
if (res == nullptr) {
auto init_value = init_value_;
res = ::new (static_cast<void*>(string_buf_))
std::string(init_value.ptr, init_value.size);
inited_.store(res, std::memory_order_release);
}
mu.Unlock();
return *res;
}
std::string* ArenaStringPtr::SetAndReturnNewString() {
std::string* new_string = new std::string();
tagged_ptr_.Set(new_string);
return new_string;
}
void ArenaStringPtr::DestroyNoArenaSlowPath() { delete UnsafeMutablePointer(); }
void ArenaStringPtr::Set(const std::string* default_value,
ConstStringParam value, ::google::protobuf::Arena* arena) {
if (IsDefault(default_value)) {
tagged_ptr_.Set(Arena::Create<std::string>(arena, value));
} else {
UnsafeMutablePointer()->assign(value.data(), value.length());
}
}
void ArenaStringPtr::Set(const std::string* default_value, std::string&& value,
::google::protobuf::Arena* arena) {
if (IsDefault(default_value)) {
if (arena == nullptr) {
tagged_ptr_.Set(new std::string(std::move(value)));
} else {
tagged_ptr_.Set(Arena::Create<std::string>(arena, std::move(value)));
}
} else if (IsDonatedString()) {
std::string* current = tagged_ptr_.Get();
auto* s = new (current) std::string(std::move(value));
arena->OwnDestructor(s);
tagged_ptr_.Set(s);
} else /* !IsDonatedString() */ {
*UnsafeMutablePointer() = std::move(value);
}
}
void ArenaStringPtr::Set(EmptyDefault, ConstStringParam value,
::google::protobuf::Arena* arena) {
Set(&GetEmptyStringAlreadyInited(), value, arena);
}
void ArenaStringPtr::Set(EmptyDefault, std::string&& value,
::google::protobuf::Arena* arena) {
Set(&GetEmptyStringAlreadyInited(), std::move(value), arena);
}
void ArenaStringPtr::Set(NonEmptyDefault, ConstStringParam value,
::google::protobuf::Arena* arena) {
Set(nullptr, value, arena);
}
void ArenaStringPtr::Set(NonEmptyDefault, std::string&& value,
::google::protobuf::Arena* arena) {
Set(nullptr, std::move(value), arena);
}
std::string* ArenaStringPtr::Mutable(EmptyDefault, ::google::protobuf::Arena* arena) {
if (!IsDonatedString() && !IsDefault(&GetEmptyStringAlreadyInited())) {
return UnsafeMutablePointer();
} else {
return MutableSlow(arena);
}
}
std::string* ArenaStringPtr::Mutable(const LazyString& default_value,
::google::protobuf::Arena* arena) {
if (!IsDonatedString() && !IsDefault(nullptr)) {
return UnsafeMutablePointer();
} else {
return MutableSlow(arena, default_value);
}
}
std::string* ArenaStringPtr::MutableNoCopy(const std::string* default_value,
::google::protobuf::Arena* arena) {
if (!IsDonatedString() && !IsDefault(default_value)) {
return UnsafeMutablePointer();
} else {
GOOGLE_DCHECK(IsDefault(default_value));
// Allocate empty. The contents are not relevant.
std::string* new_string = Arena::Create<std::string>(arena);
tagged_ptr_.Set(new_string);
return new_string;
}
}
template <typename... Lazy>
std::string* ArenaStringPtr::MutableSlow(::google::protobuf::Arena* arena,
const Lazy&... lazy_default) {
const std::string* const default_value =
sizeof...(Lazy) == 0 ? &GetEmptyStringAlreadyInited() : nullptr;
GOOGLE_DCHECK(IsDefault(default_value));
std::string* new_string =
Arena::Create<std::string>(arena, lazy_default.get()...);
tagged_ptr_.Set(new_string);
return new_string;
}
std::string* ArenaStringPtr::Release(const std::string* default_value,
::google::protobuf::Arena* arena) {
if (IsDefault(default_value)) {
return nullptr;
} else {
return ReleaseNonDefault(default_value, arena);
}
}
std::string* ArenaStringPtr::ReleaseNonDefault(const std::string* default_value,
::google::protobuf::Arena* arena) {
GOOGLE_DCHECK(!IsDefault(default_value));
if (!IsDonatedString()) {
std::string* released;
if (arena != nullptr) {
released = new std::string;
released->swap(*UnsafeMutablePointer());
} else {
released = UnsafeMutablePointer();
}
tagged_ptr_.Set(const_cast<std::string*>(default_value));
return released;
} else /* IsDonatedString() */ {
GOOGLE_DCHECK(arena != nullptr);
std::string* released = new std::string(Get());
tagged_ptr_.Set(const_cast<std::string*>(default_value));
return released;
}
}
void ArenaStringPtr::SetAllocated(const std::string* default_value,
std::string* value, ::google::protobuf::Arena* arena) {
// Release what we have first.
if (arena == nullptr && !IsDefault(default_value)) {
delete UnsafeMutablePointer();
}
if (value == nullptr) {
tagged_ptr_.Set(const_cast<std::string*>(default_value));
} else {
#ifdef NDEBUG
tagged_ptr_.Set(value);
if (arena != nullptr) {
arena->Own(value);
}
#else
// On debug builds, copy the string so the address differs. delete will
// fail if value was a stack-allocated temporary/etc., which would have
// failed when arena ran its cleanup list.
std::string* new_value = Arena::Create<std::string>(arena, *value);
delete value;
tagged_ptr_.Set(new_value);
#endif
}
}
void ArenaStringPtr::Destroy(const std::string* default_value,
::google::protobuf::Arena* arena) {
if (arena == nullptr) {
GOOGLE_DCHECK(!IsDonatedString());
if (!IsDefault(default_value)) {
delete UnsafeMutablePointer();
}
}
}
void ArenaStringPtr::Destroy(EmptyDefault, ::google::protobuf::Arena* arena) {
Destroy(&GetEmptyStringAlreadyInited(), arena);
}
void ArenaStringPtr::Destroy(NonEmptyDefault, ::google::protobuf::Arena* arena) {
Destroy(nullptr, arena);
}
void ArenaStringPtr::ClearToEmpty() {
if (IsDefault(&GetEmptyStringAlreadyInited())) {
// Already set to default -- do nothing.
} else {
// Unconditionally mask away the tag.
//
// UpdateDonatedString uses assign when capacity is larger than the new
// value, which is trivially true in the donated string case.
// const_cast<std::string*>(PtrValue<std::string>())->clear();
tagged_ptr_.Get()->clear();
}
}
void ArenaStringPtr::ClearToDefault(const LazyString& default_value,
::google::protobuf::Arena* arena) {
(void)arena;
if (IsDefault(nullptr)) {
// Already set to default -- do nothing.
} else if (!IsDonatedString()) {
UnsafeMutablePointer()->assign(default_value.get());
}
}
inline void SetStrWithHeapBuffer(std::string* str, ArenaStringPtr* s) {
TaggedPtr<std::string> res;
res.Set(str);
s->UnsafeSetTaggedPointer(res);
}
const char* EpsCopyInputStream::ReadArenaString(const char* ptr,
ArenaStringPtr* s,
Arena* arena) {
GOOGLE_DCHECK(arena != nullptr);
int size = ReadSize(&ptr);
if (!ptr) return nullptr;
auto* str = Arena::Create<std::string>(arena);
ptr = ReadString(ptr, size, str);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
SetStrWithHeapBuffer(str, s);
return ptr;
}
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
+263 -345
View File
@@ -32,389 +32,307 @@
#define GOOGLE_PROTOBUF_ARENASTRING_H__
#include <string>
#include <type_traits>
#include <utility>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/port.h>
#include <google/protobuf/port_def.inc>
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/fastmem.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/port.h>
// This is the implementation of arena string fields written for the open-source
// release. The ArenaStringPtr struct below is an internal implementation class
// and *should not be used* by user code. It is used to collect string
// operations together into one place and abstract away the underlying
// string-field pointer representation, so that (for example) an alternate
// implementation that knew more about ::std::string's internals could integrate more
// closely with the arena allocator.
namespace google {
namespace protobuf {
namespace internal {
template <typename T>
class ExplicitlyConstructed;
class SwapFieldHelper;
// Lazy string instance to support string fields with non-empty default.
// These are initialized on the first call to .get().
class PROTOBUF_EXPORT LazyString {
public:
// We explicitly make LazyString an aggregate so that MSVC can do constant
// initialization on it without marking it `constexpr`.
// We do not want to use `constexpr` because it makes it harder to have extern
// storage for it and causes library bloat.
struct InitValue {
const char* ptr;
size_t size;
};
// We keep a union of the initialization value and the std::string to save on
// space. We don't need the string array after Init() is done.
union {
mutable InitValue init_value_;
alignas(std::string) mutable char string_buf_[sizeof(std::string)];
};
mutable std::atomic<const std::string*> inited_;
const std::string& get() const {
// This check generates less code than a call-once invocation.
auto* res = inited_.load(std::memory_order_acquire);
if (PROTOBUF_PREDICT_FALSE(res == nullptr)) return Init();
return *res;
struct LIBPROTOBUF_EXPORT ArenaStringPtr {
inline void Set(const ::std::string* default_value,
const ::std::string& value, ::google::protobuf::Arena* arena) {
if (ptr_ == default_value) {
CreateInstance(arena, &value);
} else {
*ptr_ = value;
}
}
private:
// Initialize the string in `string_buf_`, update `inited_` and return it.
// We return it here to avoid having to read it again in the inlined code.
const std::string& Init() const;
};
template <typename T>
class TaggedPtr {
public:
TaggedPtr() = default;
explicit constexpr TaggedPtr(const ExplicitlyConstructed<std::string>* ptr)
: ptr_(const_cast<ExplicitlyConstructed<std::string>*>(ptr)) {}
void SetTagged(T* p) {
Set(p);
ptr_ = reinterpret_cast<void*>(as_int() | 1);
}
void Set(T* p) { ptr_ = p; }
T* Get() const { return reinterpret_cast<T*>(as_int() & -2); }
bool IsTagged() const { return as_int() & 1; }
// Returned value is only safe to dereference if IsTagged() == false.
// It is safe to compare.
T* UnsafeGet() const { return static_cast<T*>(ptr_); }
bool IsNull() { return ptr_ == nullptr; }
private:
uintptr_t as_int() const { return reinterpret_cast<uintptr_t>(ptr_); }
void* ptr_;
};
static_assert(std::is_trivial<TaggedPtr<std::string>>::value,
"TaggedPtr must be trivial");
// This class encapsulates a pointer to a std::string with or without a donated
// buffer, tagged by bottom bit. It is a high-level wrapper that almost directly
// corresponds to the interface required by string fields in generated
// code. It replaces the old std::string* pointer in such cases.
//
// The object has different but similar code paths for when the default value is
// the empty string and when it is a non-empty string.
// The empty string is handled different throughout the library and there is a
// single global instance of it we can share.
//
// For fields with an empty string default value, there are three distinct
// states:
//
// - Pointer set to 'String' tag (LSB is 0), equal to
// &GetEmptyStringAlreadyInited(): field is set to its default value. Points
// to a true std::string*, but we do not own that std::string* (it's a
// globally shared instance).
//
// - Pointer set to 'String' tag (LSB is 0), but not equal to the global empty
// string: field points to a true std::string* instance that we own. This
// instance is either on the heap or on the arena (i.e. registered on
// free()/destructor-call list) as appropriate.
//
// - Pointer set to 'DonatedString' tag (LSB is 1): points to a std::string
// instance with a buffer on the arena (arena is never nullptr in this case).
//
// For fields with a non-empty string default value, there are three distinct
// states:
//
// - Pointer set to 'String' tag (LSB is 0), equal to `nullptr`:
// Field is in "default" mode and does not point to any actual instance.
// Methods that might need to create an instance of the object will pass a
// `const LazyString&` for it.
//
// - Pointer set to 'String' tag (LSB is 0), but not equal to `nullptr`:
// field points to a true std::string* instance that we own. This instance is
// either on the heap or on the arena (i.e. registered on
// free()/destructor-call list) as appropriate.
//
// - Pointer set to 'DonatedString' tag (LSB is 1): points to a std::string
// instance with a buffer on the arena (arena is never nullptr in this case).
//
// Generated code and reflection code both ensure that ptr_ is never null for
// fields with an empty default.
// Because ArenaStringPtr is used in oneof unions, its constructor is a NOP and
// so the field is always manually initialized via method calls.
//
// Side-note: why pass information about the default on every API call? Because
// we don't want to hold it in a member variable, or else this would go into
// every proto message instance. This would be a huge waste of space, since the
// default instance pointer is typically a global (static class field). We want
// the generated code to be as efficient as possible, and if we take
// the default value information as a parameter that's in practice taken from a
// static class field, and compare ptr_ to the default value, we end up with a
// single "cmp %reg, GLOBAL" in the resulting machine code. (Note that this also
// requires the String tag to be 0 so we can avoid the mask before comparing.)
struct PROTOBUF_EXPORT ArenaStringPtr {
ArenaStringPtr() = default;
explicit constexpr ArenaStringPtr(
const ExplicitlyConstructed<std::string>* default_value)
: tagged_ptr_(default_value) {}
// Some methods below are overloaded on a `default_value` and on tags.
// The tagged overloads help reduce code size in the callers in generated
// code, while the `default_value` overloads are useful from reflection.
// By-value empty struct arguments are elided in the ABI.
struct EmptyDefault {};
struct NonEmptyDefault {};
void Set(const std::string* default_value, ConstStringParam value,
::google::protobuf::Arena* arena);
void Set(const std::string* default_value, std::string&& value,
::google::protobuf::Arena* arena);
void Set(EmptyDefault, ConstStringParam value, ::google::protobuf::Arena* arena);
void Set(EmptyDefault, std::string&& value, ::google::protobuf::Arena* arena);
void Set(NonEmptyDefault, ConstStringParam value, ::google::protobuf::Arena* arena);
void Set(NonEmptyDefault, std::string&& value, ::google::protobuf::Arena* arena);
template <typename FirstParam>
void Set(FirstParam p1, const char* str, ::google::protobuf::Arena* arena) {
Set(p1, ConstStringParam(str), arena);
}
template <typename FirstParam>
void Set(FirstParam p1, const char* str, size_t size,
::google::protobuf::Arena* arena) {
ConstStringParam sp{str, size}; // for string_view and `const string &`
Set(p1, sp, arena);
}
template <typename FirstParam, typename RefWrappedType>
void Set(FirstParam p1,
std::reference_wrapper<RefWrappedType> const_string_ref,
::google::protobuf::Arena* arena) {
Set(p1, const_string_ref.get(), arena);
}
template <typename FirstParam, typename SecondParam>
void SetBytes(FirstParam p1, SecondParam&& p2, ::google::protobuf::Arena* arena) {
Set(p1, static_cast<SecondParam&&>(p2), arena);
}
template <typename FirstParam>
void SetBytes(FirstParam p1, const void* str, size_t size,
::google::protobuf::Arena* arena) {
// must work whether ConstStringParam is string_view or `const string &`
ConstStringParam sp{static_cast<const char*>(str), size};
Set(p1, sp, arena);
inline void SetLite(const ::std::string* default_value,
const ::std::string& value,
::google::protobuf::Arena* arena) {
Set(default_value, value, arena);
}
// Basic accessors.
PROTOBUF_NDEBUG_INLINE const std::string& Get() const {
// Unconditionally mask away the tag.
return *tagged_ptr_.Get();
}
PROTOBUF_NDEBUG_INLINE const std::string* GetPointer() const {
// Unconditionally mask away the tag.
return tagged_ptr_.Get();
inline const ::std::string& Get() const { return *ptr_; }
inline ::std::string* Mutable(const ::std::string* default_value,
::google::protobuf::Arena* arena) {
if (ptr_ == default_value) {
CreateInstance(arena, default_value);
}
return ptr_;
}
// For fields with an empty default value.
std::string* Mutable(EmptyDefault, ::google::protobuf::Arena* arena);
// For fields with a non-empty default value.
std::string* Mutable(const LazyString& default_value, ::google::protobuf::Arena* arena);
// Release returns a ::std::string* instance that is heap-allocated and is not
// Own()'d by any arena. If the field was not set, it returns NULL. The caller
// retains ownership. Clears this field back to NULL state. Used to implement
// release_<field>() methods on generated classes.
inline ::std::string* Release(const ::std::string* default_value,
::google::protobuf::Arena* arena) {
if (ptr_ == default_value) {
return NULL;
}
::std::string* released = NULL;
if (arena != NULL) {
// ptr_ is owned by the arena.
released = new ::std::string;
released->swap(*ptr_);
} else {
released = ptr_;
}
ptr_ = const_cast< ::std::string* >(default_value);
return released;
}
// Release returns a std::string* instance that is heap-allocated and is not
// Own()'d by any arena. If the field is not set, this returns nullptr. The
// caller retains ownership. Clears this field back to nullptr state. Used to
// implement release_<field>() methods on generated classes.
PROTOBUF_NODISCARD std::string* Release(const std::string* default_value,
::google::protobuf::Arena* arena);
PROTOBUF_NODISCARD std::string* ReleaseNonDefault(
const std::string* default_value, ::google::protobuf::Arena* arena);
// UnsafeArenaRelease returns a ::std::string*, but it may be arena-owned (i.e.
// have its destructor already registered) if arena != NULL. If the field was
// not set, this returns NULL. This method clears this field back to NULL
// state. Used to implement unsafe_arena_release_<field>() methods on
// generated classes.
inline ::std::string* UnsafeArenaRelease(const ::std::string* default_value,
::google::protobuf::Arena* /* arena */) {
if (ptr_ == default_value) {
return NULL;
}
::std::string* released = ptr_;
ptr_ = const_cast< ::std::string* >(default_value);
return released;
}
// Takes a std::string that is heap-allocated, and takes ownership. The
// std::string's destructor is registered with the arena. Used to implement
// Takes a string that is heap-allocated, and takes ownership. The string's
// destructor is registered with the arena. Used to implement
// set_allocated_<field> in generated classes.
void SetAllocated(const std::string* default_value, std::string* value,
::google::protobuf::Arena* arena);
inline void SetAllocated(const ::std::string* default_value,
::std::string* value, ::google::protobuf::Arena* arena) {
if (arena == NULL && ptr_ != default_value) {
Destroy(default_value, arena);
}
if (value != NULL) {
ptr_ = value;
if (arena != NULL) {
arena->Own(value);
}
} else {
ptr_ = const_cast< ::std::string* >(default_value);
}
}
// Takes a string that has lifetime equal to the arena's lifetime. The arena
// must be non-null. It is safe only to pass this method a value returned by
// UnsafeArenaRelease() on another field of a message in the same arena. Used
// to implement unsafe_arena_set_allocated_<field> in generated classes.
inline void UnsafeArenaSetAllocated(const ::std::string* default_value,
::std::string* value,
::google::protobuf::Arena* /* arena */) {
if (value != NULL) {
ptr_ = value;
} else {
ptr_ = const_cast< ::std::string* >(default_value);
}
}
// Swaps internal pointers. Arena-safety semantics: this is guarded by the
// logic in Swap()/UnsafeArenaSwap() at the message level, so this method is
// 'unsafe' if called directly.
inline PROTOBUF_NDEBUG_INLINE static void InternalSwap(
const std::string* default_value, ArenaStringPtr* rhs, Arena* rhs_arena,
ArenaStringPtr* lhs, Arena* lhs_arena);
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE void Swap(ArenaStringPtr* other) {
std::swap(ptr_, other->ptr_);
}
// Frees storage (if not on an arena).
void Destroy(const std::string* default_value, ::google::protobuf::Arena* arena);
void Destroy(EmptyDefault, ::google::protobuf::Arena* arena);
void Destroy(NonEmptyDefault, ::google::protobuf::Arena* arena);
inline void Destroy(const ::std::string* default_value,
::google::protobuf::Arena* arena) {
if (arena == NULL && ptr_ != default_value) {
delete ptr_;
}
}
// Clears content, but keeps allocated std::string, to avoid the overhead of
// heap operations. After this returns, the content (as seen by the user) will
// always be the empty std::string. Assumes that |default_value| is an empty
// std::string.
void ClearToEmpty();
// Clears content, but keeps allocated string if arena != NULL, to avoid the
// overhead of heap operations. After this returns, the content (as seen by
// the user) will always be the empty string. Assumes that |default_value|
// is an empty string.
inline void ClearToEmpty(const ::std::string* default_value,
::google::protobuf::Arena* /* arena */) {
if (ptr_ == default_value) {
// Already set to default (which is empty) -- do nothing.
} else {
ptr_->clear();
}
}
// Clears content, assuming that the current value is not the empty
// string default.
void ClearNonDefaultToEmpty();
// Clears content, but keeps allocated std::string if arena != nullptr, to
// avoid the overhead of heap operations. After this returns, the content
// (as seen by the user) will always be equal to |default_value|.
void ClearToDefault(const LazyString& default_value, ::google::protobuf::Arena* arena);
// Clears content, but keeps allocated string if arena != NULL, to avoid the
// overhead of heap operations. After this returns, the content (as seen by
// the user) will always be equal to |default_value|.
inline void ClearToDefault(const ::std::string* default_value,
::google::protobuf::Arena* /* arena */) {
if (ptr_ == default_value) {
// Already set to default -- do nothing.
} else {
// Have another allocated string -- rather than throwing this away and
// resetting ptr_ to the canonical default string instance, we just reuse
// this instance.
*ptr_ = *default_value;
}
}
// Called from generated code / reflection runtime only. Resets value to point
// to a default string pointer, with the semantics that this
// ArenaStringPtr does not own the pointed-to memory. Disregards initial value
// of ptr_ (so this is the *ONLY* safe method to call after construction or
// when reinitializing after becoming the active field in a oneof union).
inline void UnsafeSetDefault(const std::string* default_value);
// Returns a mutable pointer, but doesn't initialize the string to the
// default value.
std::string* MutableNoArenaNoDefault(const std::string* default_value);
// Get a mutable pointer with unspecified contents.
// Similar to `MutableNoArenaNoDefault`, but also handles the arena case.
// If the value was donated, the contents are discarded.
std::string* MutableNoCopy(const std::string* default_value,
::google::protobuf::Arena* arena);
// Destroy the string. Assumes `arena == nullptr`.
void DestroyNoArena(const std::string* default_value);
// Internal setter used only at parse time to directly set a donated string
// value.
void UnsafeSetTaggedPointer(TaggedPtr<std::string> value) {
tagged_ptr_ = value;
// to a default string pointer, with the semantics that this ArenaStringPtr
// does not own the pointed-to memory. Disregards initial value of ptr_ (so
// this is the *ONLY* safe method to call after construction or when
// reinitializing after becoming the active field in a oneof union).
inline void UnsafeSetDefault(const ::std::string* default_value) {
// Casting away 'const' is safe here: accessors ensure that ptr_ is only
// returned as a const if it is equal to default_value.
ptr_ = const_cast< ::std::string* >(default_value);
}
// Generated code only! An optimization, in certain cases the generated
// code is certain we can obtain a std::string with no default checks and
// tag tests.
std::string* UnsafeMutablePointer() PROTOBUF_RETURNS_NONNULL;
inline bool IsDefault(const std::string* default_value) const {
// Relies on the fact that kPtrTagString == 0, so if IsString(), ptr_ is the
// actual std::string pointer (and if !IsString(), ptr_ will never be equal
// to any aligned |default_value| pointer). The key is that we want to avoid
// masking in the fastpath const-pointer Get() case for non-arena code.
return tagged_ptr_.UnsafeGet() == default_value;
// The 'NoArena' variants of methods below assume arena == NULL and are
// optimized to provide very little overhead relative to a raw string pointer
// (while still being in-memory compatible with other code that assumes
// ArenaStringPtr). Note the invariant that a class instance that has only
// ever been mutated by NoArena methods must *only* be in the String state
// (i.e., tag bits are not used), *NEVER* ArenaString. This allows all
// tagged-pointer manipulations to be avoided.
inline void SetNoArena(const ::std::string* default_value,
const ::std::string& value) {
if (ptr_ == default_value) {
CreateInstanceNoArena(&value);
} else {
*ptr_ = value;
}
}
#if LANG_CXX11
void SetNoArena(const ::std::string* default_value, ::std::string&& value) {
if (IsDefault(default_value)) {
ptr_ = new ::std::string(std::move(value));
} else {
*ptr_ = std::move(value);
}
}
#endif
void AssignWithDefault(const ::std::string* default_value, ArenaStringPtr value);
inline const ::std::string& GetNoArena() const { return *ptr_; }
inline ::std::string* MutableNoArena(const ::std::string* default_value) {
if (ptr_ == default_value) {
CreateInstanceNoArena(default_value);
}
return ptr_;
}
inline ::std::string* ReleaseNoArena(const ::std::string* default_value) {
if (ptr_ == default_value) {
return NULL;
} else {
::std::string* released = ptr_;
ptr_ = const_cast< ::std::string* >(default_value);
return released;
}
}
inline void SetAllocatedNoArena(const ::std::string* default_value,
::std::string* value) {
if (ptr_ != default_value) {
delete ptr_;
}
if (value != NULL) {
ptr_ = value;
} else {
ptr_ = const_cast< ::std::string* >(default_value);
}
}
inline void DestroyNoArena(const ::std::string* default_value) {
if (ptr_ != default_value) {
delete ptr_;
}
}
inline void ClearToEmptyNoArena(const ::std::string* default_value) {
if (ptr_ == default_value) {
// Nothing: already equal to default (which is the empty string).
} else {
ptr_->clear();
}
}
inline void ClearToDefaultNoArena(const ::std::string* default_value) {
if (ptr_ == default_value) {
// Nothing: already set to default.
} else {
// Reuse existing allocated instance.
*ptr_ = *default_value;
}
}
// Internal accessor used only at parse time to provide direct access to the
// raw pointer from the shared parse routine (in the non-arenas case). The
// parse routine does the string allocation in order to save code size in the
// generated parsing code.
inline ::std::string** UnsafeRawStringPointer() {
return &ptr_;
}
inline bool IsDefault(const ::std::string* default_value) const {
return ptr_ == default_value;
}
private:
TaggedPtr<std::string> tagged_ptr_;
::std::string* ptr_;
bool IsDonatedString() const { return false; }
// Swaps tagged pointer without debug hardening. This is to allow python
// protobuf to maintain pointer stability even in DEBUG builds.
inline PROTOBUF_NDEBUG_INLINE static void UnsafeShallowSwap(
ArenaStringPtr* rhs, ArenaStringPtr* lhs) {
std::swap(lhs->tagged_ptr_, rhs->tagged_ptr_);
GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
void CreateInstance(::google::protobuf::Arena* arena,
const ::std::string* initial_value) {
GOOGLE_DCHECK(initial_value != NULL);
ptr_ = new ::std::string(*initial_value);
if (arena != NULL) {
arena->Own(ptr_);
}
}
GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
void CreateInstanceNoArena(const ::std::string* initial_value) {
GOOGLE_DCHECK(initial_value != NULL);
ptr_ = new ::std::string(*initial_value);
}
friend class ::google::protobuf::internal::SwapFieldHelper;
// Slow paths.
// MutableSlow requires that !IsString() || IsDefault
// Variadic to support 0 args for EmptyDefault and 1 arg for LazyString.
template <typename... Lazy>
std::string* MutableSlow(::google::protobuf::Arena* arena, const Lazy&... lazy_default);
// Sets value to a newly allocated string and returns it
std::string* SetAndReturnNewString();
// Destroys the non-default string value out-of-line
void DestroyNoArenaSlowPath();
};
inline void ArenaStringPtr::UnsafeSetDefault(const std::string* value) {
tagged_ptr_.Set(const_cast<std::string*>(value));
}
// Make sure rhs_arena allocated rhs, and lhs_arena allocated lhs.
inline PROTOBUF_NDEBUG_INLINE void ArenaStringPtr::InternalSwap( //
const std::string* default_value, //
ArenaStringPtr* rhs, Arena* rhs_arena, //
ArenaStringPtr* lhs, Arena* lhs_arena) {
// Silence unused variable warnings in release buildls.
(void)default_value;
(void)rhs_arena;
(void)lhs_arena;
std::swap(lhs->tagged_ptr_, rhs->tagged_ptr_);
#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
auto force_realloc = [default_value](ArenaStringPtr* p, Arena* arena) {
if (p->IsDefault(default_value)) return;
std::string* old_value = p->tagged_ptr_.Get();
std::string* new_value =
p->IsDonatedString()
? Arena::Create<std::string>(arena, *old_value)
: Arena::Create<std::string>(arena, std::move(*old_value));
if (arena == nullptr) delete old_value;
p->tagged_ptr_.Set(new_value);
};
// Because, at this point, tagged_ptr_ has been swapped, arena should also be
// swapped.
force_realloc(lhs, rhs_arena);
force_realloc(rhs, lhs_arena);
#endif // PROTOBUF_FORCE_COPY_IN_SWAP
}
inline void ArenaStringPtr::ClearNonDefaultToEmpty() {
// Unconditionally mask away the tag.
tagged_ptr_.Get()->clear();
}
inline std::string* ArenaStringPtr::MutableNoArenaNoDefault(
const std::string* default_value) {
// VERY IMPORTANT for performance and code size: this will reduce to a member
// variable load, a pointer check (against |default_value|, in practice a
// static global) and a branch to the slowpath (which calls operator new and
// the ctor). DO NOT add any tagged-pointer operations here.
if (IsDefault(default_value)) {
return SetAndReturnNewString();
} else {
return UnsafeMutablePointer();
}
}
inline void ArenaStringPtr::DestroyNoArena(const std::string* default_value) {
if (!IsDefault(default_value)) {
DestroyNoArenaSlowPath();
}
}
inline std::string* ArenaStringPtr::UnsafeMutablePointer() {
GOOGLE_DCHECK(!tagged_ptr_.IsTagged());
GOOGLE_DCHECK(tagged_ptr_.UnsafeGet() != nullptr);
return tagged_ptr_.UnsafeGet();
}
} // namespace internal
} // namespace protobuf
namespace protobuf {
namespace internal {
inline void ArenaStringPtr::AssignWithDefault(const ::std::string* default_value,
ArenaStringPtr value) {
const ::std::string* me = *UnsafeRawStringPointer();
const ::std::string* other = *value.UnsafeRawStringPointer();
// If the pointers are the same then do nothing.
if (me != other) {
SetNoArena(default_value, value.GetNoArena());
}
}
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_ARENASTRING_H__
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+91 -99
View File
@@ -44,12 +44,6 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/port_def.inc>
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
namespace google {
namespace protobuf {
@@ -68,27 +62,27 @@ class MergedDescriptorDatabase;
// calling DescriptorPool::BuildFile() for each one. Instead, a DescriptorPool
// can be created which wraps a DescriptorDatabase and only builds particular
// descriptors when they are needed.
class PROTOBUF_EXPORT DescriptorDatabase {
class LIBPROTOBUF_EXPORT DescriptorDatabase {
public:
inline DescriptorDatabase() {}
virtual ~DescriptorDatabase();
// Find a file by file name. Fills in in *output and returns true if found.
// Otherwise, returns false, leaving the contents of *output undefined.
virtual bool FindFileByName(const std::string& filename,
virtual bool FindFileByName(const string& filename,
FileDescriptorProto* output) = 0;
// Find the file that declares the given fully-qualified symbol name.
// If found, fills in *output and returns true, otherwise returns false
// and leaves *output undefined.
virtual bool FindFileContainingSymbol(const std::string& symbol_name,
virtual bool FindFileContainingSymbol(const string& symbol_name,
FileDescriptorProto* output) = 0;
// Find the file which defines an extension extending the given message type
// with the given field number. If found, fills in *output and returns true,
// otherwise returns false and leaves *output undefined. containing_type
// must be a fully-qualified type name.
virtual bool FindFileContainingExtension(const std::string& containing_type,
virtual bool FindFileContainingExtension(const string& containing_type,
int field_number,
FileDescriptorProto* output) = 0;
@@ -102,7 +96,7 @@ class PROTOBUF_EXPORT DescriptorDatabase {
//
// This method has a default implementation that always returns
// false.
virtual bool FindAllExtensionNumbers(const std::string& /* extendee_type */,
virtual bool FindAllExtensionNumbers(const string& /* extendee_type */,
std::vector<int>* /* output */) {
return false;
}
@@ -116,24 +110,10 @@ class PROTOBUF_EXPORT DescriptorDatabase {
//
// This method has a default implementation that always returns
// false.
virtual bool FindAllFileNames(std::vector<std::string>* /*output*/) {
virtual bool FindAllFileNames(std::vector<string>* output) {
return false;
}
// Finds the package names and appends them to the output in an
// undefined order. This method is best-effort: it's not guaranteed that the
// database will find all packages. Returns true if the database supports
// searching all package names, otherwise returns false and leaves output
// unchanged.
bool FindAllPackageNames(std::vector<std::string>* output);
// Finds the message names and appends them to the output in an
// undefined order. This method is best-effort: it's not guaranteed that the
// database will find all messages. Returns true if the database supports
// searching all message names, otherwise returns false and leaves output
// unchanged.
bool FindAllMessageNames(std::vector<std::string>* output);
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorDatabase);
};
@@ -159,10 +139,10 @@ class PROTOBUF_EXPORT DescriptorDatabase {
// FileDescriptor::CopyTo()) will always use fully-qualified names for all
// types. You only need to worry if you are constructing FileDescriptorProtos
// yourself, or are calling compiler::Parser directly.
class PROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase {
class LIBPROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase {
public:
SimpleDescriptorDatabase();
~SimpleDescriptorDatabase() override;
~SimpleDescriptorDatabase();
// Adds the FileDescriptorProto to the database, making a copy. The object
// can be deleted after Add() returns. Returns false if the file conflicted
@@ -174,19 +154,20 @@ class PROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase {
bool AddAndOwn(const FileDescriptorProto* file);
// implements DescriptorDatabase -----------------------------------
bool FindFileByName(const std::string& filename,
FileDescriptorProto* output) override;
bool FindFileContainingSymbol(const std::string& symbol_name,
FileDescriptorProto* output) override;
bool FindFileContainingExtension(const std::string& containing_type,
bool FindFileByName(const string& filename,
FileDescriptorProto* output);
bool FindFileContainingSymbol(const string& symbol_name,
FileDescriptorProto* output);
bool FindFileContainingExtension(const string& containing_type,
int field_number,
FileDescriptorProto* output) override;
bool FindAllExtensionNumbers(const std::string& extendee_type,
std::vector<int>* output) override;
bool FindAllFileNames(std::vector<std::string>* output) override;
FileDescriptorProto* output);
bool FindAllExtensionNumbers(const string& extendee_type,
std::vector<int>* output);
private:
// So that it can use DescriptorIndex.
friend class EncodedDescriptorDatabase;
// An index mapping file names, symbol names, and extension numbers to
// some sort of values.
template <typename Value>
@@ -194,24 +175,24 @@ class PROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase {
public:
// Helpers to recursively add particular descriptors and all their contents
// to the index.
bool AddFile(const FileDescriptorProto& file, Value value);
bool AddSymbol(const std::string& name, Value value);
bool AddNestedExtensions(const std::string& filename,
const DescriptorProto& message_type, Value value);
bool AddExtension(const std::string& filename,
const FieldDescriptorProto& field, Value value);
bool AddFile(const FileDescriptorProto& file,
Value value);
bool AddSymbol(const string& name, Value value);
bool AddNestedExtensions(const DescriptorProto& message_type,
Value value);
bool AddExtension(const FieldDescriptorProto& field,
Value value);
Value FindFile(const std::string& filename);
Value FindSymbol(const std::string& name);
Value FindExtension(const std::string& containing_type, int field_number);
bool FindAllExtensionNumbers(const std::string& containing_type,
Value FindFile(const string& filename);
Value FindSymbol(const string& name);
Value FindExtension(const string& containing_type, int field_number);
bool FindAllExtensionNumbers(const string& containing_type,
std::vector<int>* output);
void FindAllFileNames(std::vector<std::string>* output);
private:
std::map<std::string, Value> by_name_;
std::map<std::string, Value> by_symbol_;
std::map<std::pair<std::string, int>, Value> by_extension_;
std::map<string, Value> by_name_;
std::map<string, Value> by_symbol_;
std::map<std::pair<string, int>, Value> by_extension_;
// Invariant: The by_symbol_ map does not contain any symbols which are
// prefixes of other symbols in the map. For example, "foo.bar" is a
@@ -233,7 +214,7 @@ class PROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase {
// will find it. Proof:
// 1) Define the "search key" to be the key we are looking for, the "found
// key" to be the key found in step (1), and the "match key" to be the
// key which actually matches the search key (i.e. the key we're trying
// key which actually matches the serach key (i.e. the key we're trying
// to find).
// 2) The found key must be less than or equal to the search key by
// definition.
@@ -263,14 +244,30 @@ class PROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase {
// That symbol cannot be a super-symbol of the search key since if it were,
// then it would be a match, and we're assuming the match key doesn't exist.
// Therefore, step 2 will correctly return no match.
// Find the last entry in the by_symbol_ map whose key is less than or
// equal to the given name.
typename std::map<string, Value>::iterator FindLastLessOrEqual(
const string& name);
// True if either the arguments are equal or super_symbol identifies a
// parent symbol of sub_symbol (e.g. "foo.bar" is a parent of
// "foo.bar.baz", but not a parent of "foo.barbaz").
bool IsSubSymbol(const string& sub_symbol, const string& super_symbol);
// Returns true if and only if all characters in the name are alphanumerics,
// underscores, or periods.
bool ValidateSymbolName(const string& name);
};
DescriptorIndex<const FileDescriptorProto*> index_;
std::vector<std::unique_ptr<const FileDescriptorProto>> files_to_delete_;
// If file is non-nullptr, copy it into *output and return true, otherwise
DescriptorIndex<const FileDescriptorProto*> index_;
std::vector<const FileDescriptorProto*> files_to_delete_;
// If file is non-NULL, copy it into *output and return true, otherwise
// return false.
bool MaybeCopy(const FileDescriptorProto* file, FileDescriptorProto* output);
bool MaybeCopy(const FileDescriptorProto* file,
FileDescriptorProto* output);
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SimpleDescriptorDatabase);
};
@@ -280,10 +277,10 @@ class PROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase {
//
// The same caveats regarding FindFileContainingExtension() apply as with
// SimpleDescriptorDatabase.
class PROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase {
class LIBPROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase {
public:
EncodedDescriptorDatabase();
~EncodedDescriptorDatabase() override;
~EncodedDescriptorDatabase();
// Adds the FileDescriptorProto to the database. The descriptor is provided
// in encoded form. The database does not make a copy of the bytes, nor
@@ -298,30 +295,27 @@ class PROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase {
bool AddCopy(const void* encoded_file_descriptor, int size);
// Like FindFileContainingSymbol but returns only the name of the file.
bool FindNameOfFileContainingSymbol(const std::string& symbol_name,
std::string* output);
bool FindNameOfFileContainingSymbol(const string& symbol_name,
string* output);
// implements DescriptorDatabase -----------------------------------
bool FindFileByName(const std::string& filename,
FileDescriptorProto* output) override;
bool FindFileContainingSymbol(const std::string& symbol_name,
FileDescriptorProto* output) override;
bool FindFileContainingExtension(const std::string& containing_type,
bool FindFileByName(const string& filename,
FileDescriptorProto* output);
bool FindFileContainingSymbol(const string& symbol_name,
FileDescriptorProto* output);
bool FindFileContainingExtension(const string& containing_type,
int field_number,
FileDescriptorProto* output) override;
bool FindAllExtensionNumbers(const std::string& extendee_type,
std::vector<int>* output) override;
bool FindAllFileNames(std::vector<std::string>* output) override;
FileDescriptorProto* output);
bool FindAllExtensionNumbers(const string& extendee_type,
std::vector<int>* output);
private:
class DescriptorIndex;
// Keep DescriptorIndex by pointer to hide the implementation to keep a
// cleaner header.
std::unique_ptr<DescriptorIndex> index_;
SimpleDescriptorDatabase::DescriptorIndex<std::pair<const void*, int> >
index_;
std::vector<void*> files_to_delete_;
// If encoded_file.first is non-nullptr, parse the data into *output and
// return true, otherwise return false.
// If encoded_file.first is non-NULL, parse the data into *output and return
// true, otherwise return false.
bool MaybeParse(std::pair<const void*, int> encoded_file,
FileDescriptorProto* output);
@@ -329,21 +323,21 @@ class PROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase {
};
// A DescriptorDatabase that fetches files from a given pool.
class PROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase {
class LIBPROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase {
public:
explicit DescriptorPoolDatabase(const DescriptorPool& pool);
~DescriptorPoolDatabase() override;
~DescriptorPoolDatabase();
// implements DescriptorDatabase -----------------------------------
bool FindFileByName(const std::string& filename,
FileDescriptorProto* output) override;
bool FindFileContainingSymbol(const std::string& symbol_name,
FileDescriptorProto* output) override;
bool FindFileContainingExtension(const std::string& containing_type,
bool FindFileByName(const string& filename,
FileDescriptorProto* output);
bool FindFileContainingSymbol(const string& symbol_name,
FileDescriptorProto* output);
bool FindFileContainingExtension(const string& containing_type,
int field_number,
FileDescriptorProto* output) override;
bool FindAllExtensionNumbers(const std::string& extendee_type,
std::vector<int>* output) override;
FileDescriptorProto* output);
bool FindAllExtensionNumbers(const string& extendee_type,
std::vector<int>* output);
private:
const DescriptorPool& pool_;
@@ -352,7 +346,7 @@ class PROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase {
// A DescriptorDatabase that wraps two or more others. It first searches the
// first database and, if that fails, tries the second, and so on.
class PROTOBUF_EXPORT MergedDescriptorDatabase : public DescriptorDatabase {
class LIBPROTOBUF_EXPORT MergedDescriptorDatabase : public DescriptorDatabase {
public:
// Merge just two databases. The sources remain property of the caller.
MergedDescriptorDatabase(DescriptorDatabase* source1,
@@ -362,20 +356,20 @@ class PROTOBUF_EXPORT MergedDescriptorDatabase : public DescriptorDatabase {
// DescriptorDatabases need to stick around.
explicit MergedDescriptorDatabase(
const std::vector<DescriptorDatabase*>& sources);
~MergedDescriptorDatabase() override;
~MergedDescriptorDatabase();
// implements DescriptorDatabase -----------------------------------
bool FindFileByName(const std::string& filename,
FileDescriptorProto* output) override;
bool FindFileContainingSymbol(const std::string& symbol_name,
FileDescriptorProto* output) override;
bool FindFileContainingExtension(const std::string& containing_type,
bool FindFileByName(const string& filename,
FileDescriptorProto* output);
bool FindFileContainingSymbol(const string& symbol_name,
FileDescriptorProto* output);
bool FindFileContainingExtension(const string& containing_type,
int field_number,
FileDescriptorProto* output) override;
FileDescriptorProto* output);
// Merges the results of calling all databases. Returns true iff any
// of the databases returned true.
bool FindAllExtensionNumbers(const std::string& extendee_type,
std::vector<int>* output) override;
bool FindAllExtensionNumbers(const string& extendee_type,
std::vector<int>* output);
private:
@@ -384,8 +378,6 @@ class PROTOBUF_EXPORT MergedDescriptorDatabase : public DescriptorDatabase {
};
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
+431
View File
@@ -0,0 +1,431 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/protobuf/duration.proto
#include <google/protobuf/duration.pb.h>
#include <algorithm>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/wire_format.h>
// This is a temporary google only hack
#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
#include "third_party/protobuf/version.h"
#endif
// @@protoc_insertion_point(includes)
namespace google {
namespace protobuf {
class DurationDefaultTypeInternal {
public:
::google::protobuf::internal::ExplicitlyConstructed<Duration>
_instance;
} _Duration_default_instance_;
} // namespace protobuf
} // namespace google
namespace protobuf_google_2fprotobuf_2fduration_2eproto {
void InitDefaultsDurationImpl() {
GOOGLE_PROTOBUF_VERIFY_VERSION;
#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
::google::protobuf::internal::InitProtobufDefaultsForceUnique();
#else
::google::protobuf::internal::InitProtobufDefaults();
#endif // GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
{
void* ptr = &::google::protobuf::_Duration_default_instance_;
new (ptr) ::google::protobuf::Duration();
::google::protobuf::internal::OnShutdownDestroyMessage(ptr);
}
::google::protobuf::Duration::InitAsDefaultInstance();
}
void InitDefaultsDuration() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &InitDefaultsDurationImpl);
}
::google::protobuf::Metadata file_level_metadata[1];
const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
~0u, // no _has_bits_
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::Duration, _internal_metadata_),
~0u, // no _extensions_
~0u, // no _oneof_case_
~0u, // no _weak_field_map_
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::Duration, seconds_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::Duration, nanos_),
};
static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
{ 0, -1, sizeof(::google::protobuf::Duration)},
};
static ::google::protobuf::Message const * const file_default_instances[] = {
reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::_Duration_default_instance_),
};
void protobuf_AssignDescriptors() {
AddDescriptors();
::google::protobuf::MessageFactory* factory = NULL;
AssignDescriptors(
"google/protobuf/duration.proto", schemas, file_default_instances, TableStruct::offsets, factory,
file_level_metadata, NULL, NULL);
}
void protobuf_AssignDescriptorsOnce() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors);
}
void protobuf_RegisterTypes(const ::std::string&) GOOGLE_PROTOBUF_ATTRIBUTE_COLD;
void protobuf_RegisterTypes(const ::std::string&) {
protobuf_AssignDescriptorsOnce();
::google::protobuf::internal::RegisterAllTypes(file_level_metadata, 1);
}
void AddDescriptorsImpl() {
InitDefaults();
static const char descriptor[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
"\n\036google/protobuf/duration.proto\022\017google"
".protobuf\"*\n\010Duration\022\017\n\007seconds\030\001 \001(\003\022\r"
"\n\005nanos\030\002 \001(\005B|\n\023com.google.protobufB\rDu"
"rationProtoP\001Z*github.com/golang/protobu"
"f/ptypes/duration\370\001\001\242\002\003GPB\252\002\036Google.Prot"
"obuf.WellKnownTypesb\006proto3"
};
::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
descriptor, 227);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"google/protobuf/duration.proto", &protobuf_RegisterTypes);
}
void AddDescriptors() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);
}
// Force AddDescriptors() to be called at dynamic initialization time.
struct StaticDescriptorInitializer {
StaticDescriptorInitializer() {
AddDescriptors();
}
} static_descriptor_initializer;
} // namespace protobuf_google_2fprotobuf_2fduration_2eproto
namespace google {
namespace protobuf {
// ===================================================================
void Duration::InitAsDefaultInstance() {
}
#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int Duration::kSecondsFieldNumber;
const int Duration::kNanosFieldNumber;
#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Duration::Duration()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
::protobuf_google_2fprotobuf_2fduration_2eproto::InitDefaultsDuration();
}
SharedCtor();
// @@protoc_insertion_point(constructor:google.protobuf.Duration)
}
Duration::Duration(::google::protobuf::Arena* arena)
: ::google::protobuf::Message(),
_internal_metadata_(arena) {
::protobuf_google_2fprotobuf_2fduration_2eproto::InitDefaultsDuration();
SharedCtor();
RegisterArenaDtor(arena);
// @@protoc_insertion_point(arena_constructor:google.protobuf.Duration)
}
Duration::Duration(const Duration& from)
: ::google::protobuf::Message(),
_internal_metadata_(NULL),
_cached_size_(0) {
_internal_metadata_.MergeFrom(from._internal_metadata_);
::memcpy(&seconds_, &from.seconds_,
static_cast<size_t>(reinterpret_cast<char*>(&nanos_) -
reinterpret_cast<char*>(&seconds_)) + sizeof(nanos_));
// @@protoc_insertion_point(copy_constructor:google.protobuf.Duration)
}
void Duration::SharedCtor() {
::memset(&seconds_, 0, static_cast<size_t>(
reinterpret_cast<char*>(&nanos_) -
reinterpret_cast<char*>(&seconds_)) + sizeof(nanos_));
_cached_size_ = 0;
}
Duration::~Duration() {
// @@protoc_insertion_point(destructor:google.protobuf.Duration)
SharedDtor();
}
void Duration::SharedDtor() {
GOOGLE_DCHECK(GetArenaNoVirtual() == NULL);
}
void Duration::ArenaDtor(void* object) {
Duration* _this = reinterpret_cast< Duration* >(object);
(void)_this;
}
void Duration::RegisterArenaDtor(::google::protobuf::Arena* arena) {
}
void Duration::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
}
const ::google::protobuf::Descriptor* Duration::descriptor() {
::protobuf_google_2fprotobuf_2fduration_2eproto::protobuf_AssignDescriptorsOnce();
return ::protobuf_google_2fprotobuf_2fduration_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
}
const Duration& Duration::default_instance() {
::protobuf_google_2fprotobuf_2fduration_2eproto::InitDefaultsDuration();
return *internal_default_instance();
}
Duration* Duration::New(::google::protobuf::Arena* arena) const {
return ::google::protobuf::Arena::CreateMessage<Duration>(arena);
}
void Duration::Clear() {
// @@protoc_insertion_point(message_clear_start:google.protobuf.Duration)
::google::protobuf::uint32 cached_has_bits = 0;
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
::memset(&seconds_, 0, static_cast<size_t>(
reinterpret_cast<char*>(&nanos_) -
reinterpret_cast<char*>(&seconds_)) + sizeof(nanos_));
_internal_metadata_.Clear();
}
bool Duration::MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) {
#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
// @@protoc_insertion_point(parse_start:google.protobuf.Duration)
for (;;) {
::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
tag = p.first;
if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// int64 seconds = 1;
case 1: {
if (static_cast< ::google::protobuf::uint8>(tag) ==
static_cast< ::google::protobuf::uint8>(8u /* 8 & 0xFF */)) {
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
input, &seconds_)));
} else {
goto handle_unusual;
}
break;
}
// int32 nanos = 2;
case 2: {
if (static_cast< ::google::protobuf::uint8>(tag) ==
static_cast< ::google::protobuf::uint8>(16u /* 16 & 0xFF */)) {
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
input, &nanos_)));
} else {
goto handle_unusual;
}
break;
}
default: {
handle_unusual:
if (tag == 0) {
goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, _internal_metadata_.mutable_unknown_fields()));
break;
}
}
}
success:
// @@protoc_insertion_point(parse_success:google.protobuf.Duration)
return true;
failure:
// @@protoc_insertion_point(parse_failure:google.protobuf.Duration)
return false;
#undef DO_
}
void Duration::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
// @@protoc_insertion_point(serialize_start:google.protobuf.Duration)
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
// int64 seconds = 1;
if (this->seconds() != 0) {
::google::protobuf::internal::WireFormatLite::WriteInt64(1, this->seconds(), output);
}
// int32 nanos = 2;
if (this->nanos() != 0) {
::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->nanos(), output);
}
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), output);
}
// @@protoc_insertion_point(serialize_end:google.protobuf.Duration)
}
::google::protobuf::uint8* Duration::InternalSerializeWithCachedSizesToArray(
bool deterministic, ::google::protobuf::uint8* target) const {
(void)deterministic; // Unused
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Duration)
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
// int64 seconds = 1;
if (this->seconds() != 0) {
target = ::google::protobuf::internal::WireFormatLite::WriteInt64ToArray(1, this->seconds(), target);
}
// int32 nanos = 2;
if (this->nanos() != 0) {
target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->nanos(), target);
}
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), target);
}
// @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Duration)
return target;
}
size_t Duration::ByteSizeLong() const {
// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Duration)
size_t total_size = 0;
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()));
}
// int64 seconds = 1;
if (this->seconds() != 0) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::Int64Size(
this->seconds());
}
// int32 nanos = 2;
if (this->nanos() != 0) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::Int32Size(
this->nanos());
}
int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = cached_size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
return total_size;
}
void Duration::MergeFrom(const ::google::protobuf::Message& from) {
// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Duration)
GOOGLE_DCHECK_NE(&from, this);
const Duration* source =
::google::protobuf::internal::DynamicCastToGenerated<const Duration>(
&from);
if (source == NULL) {
// @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Duration)
::google::protobuf::internal::ReflectionOps::Merge(from, this);
} else {
// @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Duration)
MergeFrom(*source);
}
}
void Duration::MergeFrom(const Duration& from) {
// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Duration)
GOOGLE_DCHECK_NE(&from, this);
_internal_metadata_.MergeFrom(from._internal_metadata_);
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
if (from.seconds() != 0) {
set_seconds(from.seconds());
}
if (from.nanos() != 0) {
set_nanos(from.nanos());
}
}
void Duration::CopyFrom(const ::google::protobuf::Message& from) {
// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Duration)
if (&from == this) return;
Clear();
MergeFrom(from);
}
void Duration::CopyFrom(const Duration& from) {
// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Duration)
if (&from == this) return;
Clear();
MergeFrom(from);
}
bool Duration::IsInitialized() const {
return true;
}
void Duration::Swap(Duration* other) {
if (other == this) return;
if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
InternalSwap(other);
} else {
Duration* temp = New(GetArenaNoVirtual());
temp->MergeFrom(*other);
other->CopyFrom(*this);
InternalSwap(temp);
if (GetArenaNoVirtual() == NULL) {
delete temp;
}
}
}
void Duration::UnsafeArenaSwap(Duration* other) {
if (other == this) return;
GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
InternalSwap(other);
}
void Duration::InternalSwap(Duration* other) {
using std::swap;
swap(seconds_, other->seconds_);
swap(nanos_, other->nanos_);
_internal_metadata_.Swap(&other->_internal_metadata_);
swap(_cached_size_, other->_cached_size_);
}
::google::protobuf::Metadata Duration::GetMetadata() const {
protobuf_google_2fprotobuf_2fduration_2eproto::protobuf_AssignDescriptorsOnce();
return ::protobuf_google_2fprotobuf_2fduration_2eproto::file_level_metadata[kIndexInFileMessages];
}
// @@protoc_insertion_point(namespace_scope)
} // namespace protobuf
} // namespace google
// @@protoc_insertion_point(global_scope)
+232
View File
@@ -0,0 +1,232 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/protobuf/duration.proto
#ifndef PROTOBUF_google_2fprotobuf_2fduration_2eproto__INCLUDED
#define PROTOBUF_google_2fprotobuf_2fduration_2eproto__INCLUDED
#include <string>
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3005000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3005001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
#endif
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/metadata.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h> // IWYU pragma: export
#include <google/protobuf/extension_set.h> // IWYU pragma: export
#include <google/protobuf/unknown_field_set.h>
// @@protoc_insertion_point(includes)
namespace protobuf_google_2fprotobuf_2fduration_2eproto {
// Internal implementation detail -- do not use these members.
struct LIBPROTOBUF_EXPORT TableStruct {
static const ::google::protobuf::internal::ParseTableField entries[];
static const ::google::protobuf::internal::AuxillaryParseTableField aux[];
static const ::google::protobuf::internal::ParseTable schema[1];
static const ::google::protobuf::internal::FieldMetadata field_metadata[];
static const ::google::protobuf::internal::SerializationTable serialization_table[];
static const ::google::protobuf::uint32 offsets[];
};
void LIBPROTOBUF_EXPORT AddDescriptors();
void LIBPROTOBUF_EXPORT InitDefaultsDurationImpl();
void LIBPROTOBUF_EXPORT InitDefaultsDuration();
inline void LIBPROTOBUF_EXPORT InitDefaults() {
InitDefaultsDuration();
}
} // namespace protobuf_google_2fprotobuf_2fduration_2eproto
namespace google {
namespace protobuf {
class Duration;
class DurationDefaultTypeInternal;
LIBPROTOBUF_EXPORT extern DurationDefaultTypeInternal _Duration_default_instance_;
} // namespace protobuf
} // namespace google
namespace google {
namespace protobuf {
// ===================================================================
class LIBPROTOBUF_EXPORT Duration : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Duration) */ {
public:
Duration();
virtual ~Duration();
Duration(const Duration& from);
inline Duration& operator=(const Duration& from) {
CopyFrom(from);
return *this;
}
#if LANG_CXX11
Duration(Duration&& from) noexcept
: Duration() {
*this = ::std::move(from);
}
inline Duration& operator=(Duration&& from) noexcept {
if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
if (this != &from) InternalSwap(&from);
} else {
CopyFrom(from);
}
return *this;
}
#endif
inline ::google::protobuf::Arena* GetArena() const PROTOBUF_FINAL {
return GetArenaNoVirtual();
}
inline void* GetMaybeArenaPointer() const PROTOBUF_FINAL {
return MaybeArenaPtr();
}
static const ::google::protobuf::Descriptor* descriptor();
static const Duration& default_instance();
static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY
static inline const Duration* internal_default_instance() {
return reinterpret_cast<const Duration*>(
&_Duration_default_instance_);
}
static PROTOBUF_CONSTEXPR int const kIndexInFileMessages =
0;
void UnsafeArenaSwap(Duration* other);
void Swap(Duration* other);
friend void swap(Duration& a, Duration& b) {
a.Swap(&b);
}
// implements Message ----------------------------------------------
inline Duration* New() const PROTOBUF_FINAL { return New(NULL); }
Duration* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
void CopyFrom(const Duration& from);
void MergeFrom(const Duration& from);
void Clear() PROTOBUF_FINAL;
bool IsInitialized() const PROTOBUF_FINAL;
size_t ByteSizeLong() const PROTOBUF_FINAL;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
private:
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const PROTOBUF_FINAL;
void InternalSwap(Duration* other);
protected:
explicit Duration(::google::protobuf::Arena* arena);
private:
static void ArenaDtor(void* object);
inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return _internal_metadata_.arena();
}
inline void* MaybeArenaPtr() const {
return _internal_metadata_.raw_arena_ptr();
}
public:
::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
// nested types ----------------------------------------------------
// accessors -------------------------------------------------------
// int64 seconds = 1;
void clear_seconds();
static const int kSecondsFieldNumber = 1;
::google::protobuf::int64 seconds() const;
void set_seconds(::google::protobuf::int64 value);
// int32 nanos = 2;
void clear_nanos();
static const int kNanosFieldNumber = 2;
::google::protobuf::int32 nanos() const;
void set_nanos(::google::protobuf::int32 value);
// @@protoc_insertion_point(class_scope:google.protobuf.Duration)
private:
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
template <typename T> friend class ::google::protobuf::Arena::InternalHelper;
typedef void InternalArenaConstructable_;
typedef void DestructorSkippable_;
::google::protobuf::int64 seconds_;
::google::protobuf::int32 nanos_;
mutable int _cached_size_;
friend struct ::protobuf_google_2fprotobuf_2fduration_2eproto::TableStruct;
friend void ::protobuf_google_2fprotobuf_2fduration_2eproto::InitDefaultsDurationImpl();
};
// ===================================================================
// ===================================================================
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif // __GNUC__
// Duration
// int64 seconds = 1;
inline void Duration::clear_seconds() {
seconds_ = GOOGLE_LONGLONG(0);
}
inline ::google::protobuf::int64 Duration::seconds() const {
// @@protoc_insertion_point(field_get:google.protobuf.Duration.seconds)
return seconds_;
}
inline void Duration::set_seconds(::google::protobuf::int64 value) {
seconds_ = value;
// @@protoc_insertion_point(field_set:google.protobuf.Duration.seconds)
}
// int32 nanos = 2;
inline void Duration::clear_nanos() {
nanos_ = 0;
}
inline ::google::protobuf::int32 Duration::nanos() const {
// @@protoc_insertion_point(field_get:google.protobuf.Duration.nanos)
return nanos_;
}
inline void Duration::set_nanos(::google::protobuf::int32 value) {
nanos_ = value;
// @@protoc_insertion_point(field_set:google.protobuf.Duration.nanos)
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif // __GNUC__
// @@protoc_insertion_point(namespace_scope)
} // namespace protobuf
} // namespace google
// @@protoc_insertion_point(global_scope)
#endif // PROTOBUF_google_2fprotobuf_2fduration_2eproto__INCLUDED
File diff suppressed because it is too large Load Diff
+53 -42
View File
@@ -40,27 +40,22 @@
#include <algorithm>
#include <memory>
#include <unordered_map>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <vector>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/message.h>
#include <google/protobuf/stubs/mutex.h>
#include <google/protobuf/reflection.h>
#include <google/protobuf/repeated_field.h>
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
#include <google/protobuf/port_def.inc>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/mutex.h>
namespace google {
namespace protobuf {
// Defined in other files.
class Descriptor; // descriptor.h
class DescriptorPool; // descriptor.h
class Descriptor; // descriptor.h
class DescriptorPool; // descriptor.h
// Constructs implementations of Message which can emulate types which are not
// known at compile-time.
@@ -79,7 +74,7 @@ class DescriptorPool; // descriptor.h
// encapsulates this "cache". All DynamicMessages of the same type created
// from the same factory will share the same support data. Any Descriptors
// used with a particular factory must outlive the factory.
class PROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory {
class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory {
public:
// Construct a DynamicMessageFactory that will search for extensions in
// the DescriptorPool in which the extendee is defined.
@@ -123,44 +118,62 @@ class PROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory {
// outlive the DynamicMessageFactory.
//
// The method is thread-safe.
const Message* GetPrototype(const Descriptor* type) override;
const Message* GetPrototype(const Descriptor* type);
private:
const DescriptorPool* pool_;
bool delegate_to_generated_factory_;
struct TypeInfo;
std::unordered_map<const Descriptor*, const TypeInfo*> prototypes_;
mutable internal::WrappedMutex prototypes_mutex_;
// This struct just contains a hash_map. We can't #include <google/protobuf/stubs/hash.h> from
// this header due to hacks needed for hash_map portability in the open source
// release. Namely, stubs/hash.h, which defines hash_map portably, is not a
// public header (for good reason), but dynamic_message.h is, and public
// headers may only #include other public headers.
struct PrototypeMap;
google::protobuf::scoped_ptr<PrototypeMap> prototypes_;
mutable Mutex prototypes_mutex_;
friend class DynamicMessage;
const Message* GetPrototypeNoLock(const Descriptor* type);
// Construct default oneof instance for reflection usage if oneof
// is defined.
static void ConstructDefaultOneofInstance(const Descriptor* type,
const uint32 offsets[],
void* default_oneof_instance);
// Delete default oneof instance. Called by ~DynamicMessageFactory.
static void DeleteDefaultOneofInstance(const Descriptor* type,
const uint32 offsets[],
const void* default_oneof_instance);
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessageFactory);
};
// Helper for computing a sorted list of map entries via reflection.
class PROTOBUF_EXPORT DynamicMapSorter {
class LIBPROTOBUF_EXPORT DynamicMapSorter {
public:
static std::vector<const Message*> Sort(const Message& message, int map_size,
static std::vector<const Message*> Sort(const Message& message,
int map_size,
const Reflection* reflection,
const FieldDescriptor* field) {
std::vector<const Message*> result;
result.reserve(map_size);
RepeatedFieldRef<Message> map_field =
reflection->GetRepeatedFieldRef<Message>(message, field);
for (auto it = map_field.begin(); it != map_field.end(); ++it) {
result.push_back(&*it);
std::vector<const Message*> result(static_cast<size_t>(map_size));
const RepeatedPtrField<Message>& map_field =
reflection->GetRepeatedPtrField<Message>(message, field);
size_t i = 0;
for (RepeatedPtrField<Message>::const_pointer_iterator it =
map_field.pointer_begin(); it != map_field.pointer_end(); ) {
result[i++] = *it++;
}
GOOGLE_DCHECK_EQ(result.size(), i);
MapEntryMessageComparator comparator(field->message_type());
std::stable_sort(result.begin(), result.end(), comparator);
// Complain if the keys aren't in ascending order.
#ifndef NDEBUG
for (size_t j = 1; j < static_cast<size_t>(map_size); j++) {
if (!comparator(result[j - 1], result[j])) {
GOOGLE_LOG(ERROR) << (comparator(result[j], result[j - 1])
? "internal error in map key sorting"
: "map keys are not unique");
GOOGLE_LOG(ERROR) << (comparator(result[j], result[j - 1]) ?
"internal error in map key sorting" :
"map keys are not unique");
}
}
#endif
@@ -168,7 +181,7 @@ class PROTOBUF_EXPORT DynamicMapSorter {
}
private:
class PROTOBUF_EXPORT MapEntryMessageComparator {
class LIBPROTOBUF_EXPORT MapEntryMessageComparator {
public:
explicit MapEntryMessageComparator(const Descriptor* descriptor)
: field_(descriptor->field(0)) {}
@@ -182,28 +195,28 @@ class PROTOBUF_EXPORT DynamicMapSorter {
return first < second;
}
case FieldDescriptor::CPPTYPE_INT32: {
int32_t first = reflection->GetInt32(*a, field_);
int32_t second = reflection->GetInt32(*b, field_);
int32 first = reflection->GetInt32(*a, field_);
int32 second = reflection->GetInt32(*b, field_);
return first < second;
}
case FieldDescriptor::CPPTYPE_INT64: {
int64_t first = reflection->GetInt64(*a, field_);
int64_t second = reflection->GetInt64(*b, field_);
int64 first = reflection->GetInt64(*a, field_);
int64 second = reflection->GetInt64(*b, field_);
return first < second;
}
case FieldDescriptor::CPPTYPE_UINT32: {
uint32_t first = reflection->GetUInt32(*a, field_);
uint32_t second = reflection->GetUInt32(*b, field_);
uint32 first = reflection->GetUInt32(*a, field_);
uint32 second = reflection->GetUInt32(*b, field_);
return first < second;
}
case FieldDescriptor::CPPTYPE_UINT64: {
uint64_t first = reflection->GetUInt64(*a, field_);
uint64_t second = reflection->GetUInt64(*b, field_);
uint64 first = reflection->GetUInt64(*a, field_);
uint64 second = reflection->GetUInt64(*b, field_);
return first < second;
}
case FieldDescriptor::CPPTYPE_STRING: {
std::string first = reflection->GetString(*a, field_);
std::string second = reflection->GetString(*b, field_);
string first = reflection->GetString(*a, field_);
string second = reflection->GetString(*b, field_);
return first < second;
}
default:
@@ -218,8 +231,6 @@ class PROTOBUF_EXPORT DynamicMapSorter {
};
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
+342
View File
@@ -0,0 +1,342 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/protobuf/empty.proto
#include <google/protobuf/empty.pb.h>
#include <algorithm>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/wire_format.h>
// This is a temporary google only hack
#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
#include "third_party/protobuf/version.h"
#endif
// @@protoc_insertion_point(includes)
namespace google {
namespace protobuf {
class EmptyDefaultTypeInternal {
public:
::google::protobuf::internal::ExplicitlyConstructed<Empty>
_instance;
} _Empty_default_instance_;
} // namespace protobuf
} // namespace google
namespace protobuf_google_2fprotobuf_2fempty_2eproto {
void InitDefaultsEmptyImpl() {
GOOGLE_PROTOBUF_VERIFY_VERSION;
#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
::google::protobuf::internal::InitProtobufDefaultsForceUnique();
#else
::google::protobuf::internal::InitProtobufDefaults();
#endif // GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
{
void* ptr = &::google::protobuf::_Empty_default_instance_;
new (ptr) ::google::protobuf::Empty();
::google::protobuf::internal::OnShutdownDestroyMessage(ptr);
}
::google::protobuf::Empty::InitAsDefaultInstance();
}
void InitDefaultsEmpty() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &InitDefaultsEmptyImpl);
}
::google::protobuf::Metadata file_level_metadata[1];
const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
~0u, // no _has_bits_
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::Empty, _internal_metadata_),
~0u, // no _extensions_
~0u, // no _oneof_case_
~0u, // no _weak_field_map_
};
static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
{ 0, -1, sizeof(::google::protobuf::Empty)},
};
static ::google::protobuf::Message const * const file_default_instances[] = {
reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::_Empty_default_instance_),
};
void protobuf_AssignDescriptors() {
AddDescriptors();
::google::protobuf::MessageFactory* factory = NULL;
AssignDescriptors(
"google/protobuf/empty.proto", schemas, file_default_instances, TableStruct::offsets, factory,
file_level_metadata, NULL, NULL);
}
void protobuf_AssignDescriptorsOnce() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors);
}
void protobuf_RegisterTypes(const ::std::string&) GOOGLE_PROTOBUF_ATTRIBUTE_COLD;
void protobuf_RegisterTypes(const ::std::string&) {
protobuf_AssignDescriptorsOnce();
::google::protobuf::internal::RegisterAllTypes(file_level_metadata, 1);
}
void AddDescriptorsImpl() {
InitDefaults();
static const char descriptor[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
"\n\033google/protobuf/empty.proto\022\017google.pr"
"otobuf\"\007\n\005EmptyBv\n\023com.google.protobufB\n"
"EmptyProtoP\001Z\'github.com/golang/protobuf"
"/ptypes/empty\370\001\001\242\002\003GPB\252\002\036Google.Protobuf"
".WellKnownTypesb\006proto3"
};
::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
descriptor, 183);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"google/protobuf/empty.proto", &protobuf_RegisterTypes);
}
void AddDescriptors() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);
}
// Force AddDescriptors() to be called at dynamic initialization time.
struct StaticDescriptorInitializer {
StaticDescriptorInitializer() {
AddDescriptors();
}
} static_descriptor_initializer;
} // namespace protobuf_google_2fprotobuf_2fempty_2eproto
namespace google {
namespace protobuf {
// ===================================================================
void Empty::InitAsDefaultInstance() {
}
#if !defined(_MSC_VER) || _MSC_VER >= 1900
#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
Empty::Empty()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
::protobuf_google_2fprotobuf_2fempty_2eproto::InitDefaultsEmpty();
}
SharedCtor();
// @@protoc_insertion_point(constructor:google.protobuf.Empty)
}
Empty::Empty(::google::protobuf::Arena* arena)
: ::google::protobuf::Message(),
_internal_metadata_(arena) {
::protobuf_google_2fprotobuf_2fempty_2eproto::InitDefaultsEmpty();
SharedCtor();
RegisterArenaDtor(arena);
// @@protoc_insertion_point(arena_constructor:google.protobuf.Empty)
}
Empty::Empty(const Empty& from)
: ::google::protobuf::Message(),
_internal_metadata_(NULL),
_cached_size_(0) {
_internal_metadata_.MergeFrom(from._internal_metadata_);
// @@protoc_insertion_point(copy_constructor:google.protobuf.Empty)
}
void Empty::SharedCtor() {
_cached_size_ = 0;
}
Empty::~Empty() {
// @@protoc_insertion_point(destructor:google.protobuf.Empty)
SharedDtor();
}
void Empty::SharedDtor() {
GOOGLE_DCHECK(GetArenaNoVirtual() == NULL);
}
void Empty::ArenaDtor(void* object) {
Empty* _this = reinterpret_cast< Empty* >(object);
(void)_this;
}
void Empty::RegisterArenaDtor(::google::protobuf::Arena* arena) {
}
void Empty::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
}
const ::google::protobuf::Descriptor* Empty::descriptor() {
::protobuf_google_2fprotobuf_2fempty_2eproto::protobuf_AssignDescriptorsOnce();
return ::protobuf_google_2fprotobuf_2fempty_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
}
const Empty& Empty::default_instance() {
::protobuf_google_2fprotobuf_2fempty_2eproto::InitDefaultsEmpty();
return *internal_default_instance();
}
Empty* Empty::New(::google::protobuf::Arena* arena) const {
return ::google::protobuf::Arena::CreateMessage<Empty>(arena);
}
void Empty::Clear() {
// @@protoc_insertion_point(message_clear_start:google.protobuf.Empty)
::google::protobuf::uint32 cached_has_bits = 0;
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
_internal_metadata_.Clear();
}
bool Empty::MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) {
#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
// @@protoc_insertion_point(parse_start:google.protobuf.Empty)
for (;;) {
::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
tag = p.first;
if (!p.second) goto handle_unusual;
handle_unusual:
if (tag == 0) {
goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, _internal_metadata_.mutable_unknown_fields()));
}
success:
// @@protoc_insertion_point(parse_success:google.protobuf.Empty)
return true;
failure:
// @@protoc_insertion_point(parse_failure:google.protobuf.Empty)
return false;
#undef DO_
}
void Empty::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
// @@protoc_insertion_point(serialize_start:google.protobuf.Empty)
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), output);
}
// @@protoc_insertion_point(serialize_end:google.protobuf.Empty)
}
::google::protobuf::uint8* Empty::InternalSerializeWithCachedSizesToArray(
bool deterministic, ::google::protobuf::uint8* target) const {
(void)deterministic; // Unused
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Empty)
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), target);
}
// @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Empty)
return target;
}
size_t Empty::ByteSizeLong() const {
// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Empty)
size_t total_size = 0;
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()));
}
int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = cached_size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
return total_size;
}
void Empty::MergeFrom(const ::google::protobuf::Message& from) {
// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Empty)
GOOGLE_DCHECK_NE(&from, this);
const Empty* source =
::google::protobuf::internal::DynamicCastToGenerated<const Empty>(
&from);
if (source == NULL) {
// @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Empty)
::google::protobuf::internal::ReflectionOps::Merge(from, this);
} else {
// @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Empty)
MergeFrom(*source);
}
}
void Empty::MergeFrom(const Empty& from) {
// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Empty)
GOOGLE_DCHECK_NE(&from, this);
_internal_metadata_.MergeFrom(from._internal_metadata_);
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
}
void Empty::CopyFrom(const ::google::protobuf::Message& from) {
// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Empty)
if (&from == this) return;
Clear();
MergeFrom(from);
}
void Empty::CopyFrom(const Empty& from) {
// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Empty)
if (&from == this) return;
Clear();
MergeFrom(from);
}
bool Empty::IsInitialized() const {
return true;
}
void Empty::Swap(Empty* other) {
if (other == this) return;
if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
InternalSwap(other);
} else {
Empty* temp = New(GetArenaNoVirtual());
temp->MergeFrom(*other);
other->CopyFrom(*this);
InternalSwap(temp);
if (GetArenaNoVirtual() == NULL) {
delete temp;
}
}
}
void Empty::UnsafeArenaSwap(Empty* other) {
if (other == this) return;
GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
InternalSwap(other);
}
void Empty::InternalSwap(Empty* other) {
using std::swap;
_internal_metadata_.Swap(&other->_internal_metadata_);
swap(_cached_size_, other->_cached_size_);
}
::google::protobuf::Metadata Empty::GetMetadata() const {
protobuf_google_2fprotobuf_2fempty_2eproto::protobuf_AssignDescriptorsOnce();
return ::protobuf_google_2fprotobuf_2fempty_2eproto::file_level_metadata[kIndexInFileMessages];
}
// @@protoc_insertion_point(namespace_scope)
} // namespace protobuf
} // namespace google
// @@protoc_insertion_point(global_scope)
+190
View File
@@ -0,0 +1,190 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/protobuf/empty.proto
#ifndef PROTOBUF_google_2fprotobuf_2fempty_2eproto__INCLUDED
#define PROTOBUF_google_2fprotobuf_2fempty_2eproto__INCLUDED
#include <string>
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3005000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3005001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
#endif
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/metadata.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h> // IWYU pragma: export
#include <google/protobuf/extension_set.h> // IWYU pragma: export
#include <google/protobuf/unknown_field_set.h>
// @@protoc_insertion_point(includes)
namespace protobuf_google_2fprotobuf_2fempty_2eproto {
// Internal implementation detail -- do not use these members.
struct LIBPROTOBUF_EXPORT TableStruct {
static const ::google::protobuf::internal::ParseTableField entries[];
static const ::google::protobuf::internal::AuxillaryParseTableField aux[];
static const ::google::protobuf::internal::ParseTable schema[1];
static const ::google::protobuf::internal::FieldMetadata field_metadata[];
static const ::google::protobuf::internal::SerializationTable serialization_table[];
static const ::google::protobuf::uint32 offsets[];
};
void LIBPROTOBUF_EXPORT AddDescriptors();
void LIBPROTOBUF_EXPORT InitDefaultsEmptyImpl();
void LIBPROTOBUF_EXPORT InitDefaultsEmpty();
inline void LIBPROTOBUF_EXPORT InitDefaults() {
InitDefaultsEmpty();
}
} // namespace protobuf_google_2fprotobuf_2fempty_2eproto
namespace google {
namespace protobuf {
class Empty;
class EmptyDefaultTypeInternal;
LIBPROTOBUF_EXPORT extern EmptyDefaultTypeInternal _Empty_default_instance_;
} // namespace protobuf
} // namespace google
namespace google {
namespace protobuf {
// ===================================================================
class LIBPROTOBUF_EXPORT Empty : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Empty) */ {
public:
Empty();
virtual ~Empty();
Empty(const Empty& from);
inline Empty& operator=(const Empty& from) {
CopyFrom(from);
return *this;
}
#if LANG_CXX11
Empty(Empty&& from) noexcept
: Empty() {
*this = ::std::move(from);
}
inline Empty& operator=(Empty&& from) noexcept {
if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
if (this != &from) InternalSwap(&from);
} else {
CopyFrom(from);
}
return *this;
}
#endif
inline ::google::protobuf::Arena* GetArena() const PROTOBUF_FINAL {
return GetArenaNoVirtual();
}
inline void* GetMaybeArenaPointer() const PROTOBUF_FINAL {
return MaybeArenaPtr();
}
static const ::google::protobuf::Descriptor* descriptor();
static const Empty& default_instance();
static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY
static inline const Empty* internal_default_instance() {
return reinterpret_cast<const Empty*>(
&_Empty_default_instance_);
}
static PROTOBUF_CONSTEXPR int const kIndexInFileMessages =
0;
void UnsafeArenaSwap(Empty* other);
void Swap(Empty* other);
friend void swap(Empty& a, Empty& b) {
a.Swap(&b);
}
// implements Message ----------------------------------------------
inline Empty* New() const PROTOBUF_FINAL { return New(NULL); }
Empty* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
void CopyFrom(const Empty& from);
void MergeFrom(const Empty& from);
void Clear() PROTOBUF_FINAL;
bool IsInitialized() const PROTOBUF_FINAL;
size_t ByteSizeLong() const PROTOBUF_FINAL;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
private:
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const PROTOBUF_FINAL;
void InternalSwap(Empty* other);
protected:
explicit Empty(::google::protobuf::Arena* arena);
private:
static void ArenaDtor(void* object);
inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
private:
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return _internal_metadata_.arena();
}
inline void* MaybeArenaPtr() const {
return _internal_metadata_.raw_arena_ptr();
}
public:
::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
// nested types ----------------------------------------------------
// accessors -------------------------------------------------------
// @@protoc_insertion_point(class_scope:google.protobuf.Empty)
private:
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
template <typename T> friend class ::google::protobuf::Arena::InternalHelper;
typedef void InternalArenaConstructable_;
typedef void DestructorSkippable_;
mutable int _cached_size_;
friend struct ::protobuf_google_2fprotobuf_2fempty_2eproto::TableStruct;
friend void ::protobuf_google_2fprotobuf_2fempty_2eproto::InitDefaultsEmptyImpl();
};
// ===================================================================
// ===================================================================
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif // __GNUC__
// Empty
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif // __GNUC__
// @@protoc_insertion_point(namespace_scope)
} // namespace protobuf
} // namespace google
// @@protoc_insertion_point(global_scope)
#endif // PROTOBUF_google_2fprotobuf_2fempty_2eproto__INCLUDED
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+462 -194
View File
@@ -35,47 +35,42 @@
// Contains methods defined in extension_set.h which cannot be part of the
// lite library because they use descriptors or reflection.
#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/extension_set_inl.h>
#include <google/protobuf/parse_context.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/message.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/port_def.inc>
#include <google/protobuf/wire_format_lite_inl.h>
namespace google {
namespace protobuf {
namespace internal {
// A FieldSkipper used to store unknown MessageSet fields into UnknownFieldSet.
class MessageSetFieldSkipper : public UnknownFieldSetFieldSkipper {
class MessageSetFieldSkipper
: public UnknownFieldSetFieldSkipper {
public:
explicit MessageSetFieldSkipper(UnknownFieldSet* unknown_fields)
: UnknownFieldSetFieldSkipper(unknown_fields) {}
~MessageSetFieldSkipper() override {}
virtual ~MessageSetFieldSkipper() {}
virtual bool SkipMessageSetField(io::CodedInputStream* input,
int field_number);
};
bool MessageSetFieldSkipper::SkipMessageSetField(io::CodedInputStream* input,
int field_number) {
uint32_t length;
bool MessageSetFieldSkipper::SkipMessageSetField(
io::CodedInputStream* input, int field_number) {
uint32 length;
if (!input->ReadVarint32(&length)) return false;
if (unknown_fields_ == nullptr) {
if (unknown_fields_ == NULL) {
return input->Skip(length);
} else {
return input->ReadString(unknown_fields_->AddLengthDelimited(field_number),
length);
return input->ReadString(
unknown_fields_->AddLengthDelimited(field_number), length);
}
}
@@ -89,9 +84,9 @@ class DescriptorPoolExtensionFinder : public ExtensionFinder {
MessageFactory* factory,
const Descriptor* containing_type)
: pool_(pool), factory_(factory), containing_type_(containing_type) {}
~DescriptorPoolExtensionFinder() override {}
virtual ~DescriptorPoolExtensionFinder() {}
bool Find(int number, ExtensionInfo* output) override;
virtual bool Find(int number, ExtensionInfo* output);
private:
const DescriptorPool* pool_;
@@ -100,14 +95,16 @@ class DescriptorPoolExtensionFinder : public ExtensionFinder {
};
void ExtensionSet::AppendToList(
const Descriptor* containing_type, const DescriptorPool* pool,
const Descriptor* containing_type,
const DescriptorPool* pool,
std::vector<const FieldDescriptor*>* output) const {
ForEach([containing_type, pool, &output](int number, const Extension& ext) {
for (ExtensionMap::const_iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
bool has = false;
if (ext.is_repeated) {
has = ext.GetSize() > 0;
if (iter->second.is_repeated) {
has = iter->second.GetSize() > 0;
} else {
has = !ext.is_cleared;
has = !iter->second.is_cleared;
}
if (has) {
@@ -116,13 +113,14 @@ void ExtensionSet::AppendToList(
// initialized, so they might not even be constructed until
// AppendToList() is called.
if (ext.descriptor == nullptr) {
output->push_back(pool->FindExtensionByNumber(containing_type, number));
if (iter->second.descriptor == NULL) {
output->push_back(pool->FindExtensionByNumber(
containing_type, iter->first));
} else {
output->push_back(ext.descriptor);
output->push_back(iter->second.descriptor);
}
}
});
}
}
inline FieldDescriptor::Type real_type(FieldType type) {
@@ -140,26 +138,26 @@ inline WireFormatLite::FieldType field_type(FieldType type) {
return static_cast<WireFormatLite::FieldType>(type);
}
#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \
GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED \
: FieldDescriptor::LABEL_OPTIONAL, \
FieldDescriptor::LABEL_##LABEL); \
#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \
GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED \
: FieldDescriptor::LABEL_OPTIONAL, \
FieldDescriptor::LABEL_##LABEL); \
GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), FieldDescriptor::CPPTYPE_##CPPTYPE)
const MessageLite& ExtensionSet::GetMessage(int number,
const Descriptor* message_type,
MessageFactory* factory) const {
const Extension* extension = FindOrNull(number);
if (extension == nullptr || extension->is_cleared) {
ExtensionMap::const_iterator iter = extensions_.find(number);
if (iter == extensions_.end() || iter->second.is_cleared) {
// Not present. Return the default value.
return *factory->GetPrototype(message_type);
} else {
GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
if (extension->is_lazy) {
return extension->lazymessage_value->GetMessage(
*factory->GetPrototype(message_type), arena_);
GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
if (iter->second.is_lazy) {
return iter->second.lazymessage_value->GetMessage(
*factory->GetPrototype(message_type));
} else {
return *extension->message_value;
return *iter->second.message_value;
}
}
}
@@ -183,7 +181,7 @@ MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor,
extension->is_cleared = false;
if (extension->is_lazy) {
return extension->lazymessage_value->MutableMessage(
*factory->GetPrototype(descriptor->message_type()), arena_);
*factory->GetPrototype(descriptor->message_type()));
} else {
return extension->message_value;
}
@@ -192,64 +190,63 @@ MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor,
MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor,
MessageFactory* factory) {
Extension* extension = FindOrNull(descriptor->number());
if (extension == nullptr) {
// Not present. Return nullptr.
return nullptr;
ExtensionMap::iterator iter = extensions_.find(descriptor->number());
if (iter == extensions_.end()) {
// Not present. Return NULL.
return NULL;
} else {
GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
MessageLite* ret = nullptr;
if (extension->is_lazy) {
ret = extension->lazymessage_value->ReleaseMessage(
*factory->GetPrototype(descriptor->message_type()), arena_);
if (arena_ == nullptr) {
delete extension->lazymessage_value;
GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
MessageLite* ret = NULL;
if (iter->second.is_lazy) {
ret = iter->second.lazymessage_value->ReleaseMessage(
*factory->GetPrototype(descriptor->message_type()));
if (arena_ == NULL) {
delete iter->second.lazymessage_value;
}
} else {
if (arena_ != nullptr) {
ret = extension->message_value->New();
ret->CheckTypeAndMergeFrom(*extension->message_value);
if (arena_ != NULL) {
ret = (iter->second.message_value)->New();
ret->CheckTypeAndMergeFrom(*(iter->second.message_value));
} else {
ret = extension->message_value;
ret = iter->second.message_value;
}
}
Erase(descriptor->number());
extensions_.erase(descriptor->number());
return ret;
}
}
MessageLite* ExtensionSet::UnsafeArenaReleaseMessage(
const FieldDescriptor* descriptor, MessageFactory* factory) {
Extension* extension = FindOrNull(descriptor->number());
if (extension == nullptr) {
// Not present. Return nullptr.
return nullptr;
ExtensionMap::iterator iter = extensions_.find(descriptor->number());
if (iter == extensions_.end()) {
// Not present. Return NULL.
return NULL;
} else {
GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
MessageLite* ret = nullptr;
if (extension->is_lazy) {
ret = extension->lazymessage_value->UnsafeArenaReleaseMessage(
*factory->GetPrototype(descriptor->message_type()), arena_);
if (arena_ == nullptr) {
delete extension->lazymessage_value;
GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
MessageLite* ret = NULL;
if (iter->second.is_lazy) {
ret = iter->second.lazymessage_value->UnsafeArenaReleaseMessage(
*factory->GetPrototype(descriptor->message_type()));
if (arena_ == NULL) {
delete iter->second.lazymessage_value;
}
} else {
ret = extension->message_value;
ret = iter->second.message_value;
}
Erase(descriptor->number());
extensions_.erase(descriptor->number());
return ret;
}
}
ExtensionSet::Extension* ExtensionSet::MaybeNewRepeatedExtension(
const FieldDescriptor* descriptor) {
ExtensionSet::Extension* ExtensionSet::MaybeNewRepeatedExtension(const FieldDescriptor* descriptor) {
Extension* extension;
if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) {
extension->type = descriptor->type();
GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
extension->is_repeated = true;
extension->repeated_message_value =
Arena::CreateMessage<RepeatedPtrField<MessageLite> >(arena_);
::google::protobuf::Arena::CreateMessage<RepeatedPtrField<MessageLite> >(arena_);
} else {
GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
}
@@ -262,15 +259,13 @@ MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor,
// RepeatedPtrField<Message> does not know how to Add() since it cannot
// allocate an abstract object, so we have to be tricky.
MessageLite* result =
reinterpret_cast<internal::RepeatedPtrFieldBase*>(
extension->repeated_message_value)
->AddFromCleared<GenericTypeHandler<MessageLite> >();
if (result == nullptr) {
MessageLite* result = extension->repeated_message_value
->AddFromCleared<GenericTypeHandler<MessageLite> >();
if (result == NULL) {
const MessageLite* prototype;
if (extension->repeated_message_value->empty()) {
if (extension->repeated_message_value->size() == 0) {
prototype = factory->GetPrototype(descriptor->message_type());
GOOGLE_CHECK(prototype != nullptr);
GOOGLE_CHECK(prototype != NULL);
} else {
prototype = &extension->repeated_message_value->Get(0);
}
@@ -287,22 +282,15 @@ void ExtensionSet::AddAllocatedMessage(const FieldDescriptor* descriptor,
extension->repeated_message_value->AddAllocated(new_entry);
}
void ExtensionSet::UnsafeArenaAddAllocatedMessage(
const FieldDescriptor* descriptor, MessageLite* new_entry) {
Extension* extension = MaybeNewRepeatedExtension(descriptor);
extension->repeated_message_value->UnsafeArenaAddAllocated(new_entry);
}
static bool ValidateEnumUsingDescriptor(const void* arg, int number) {
return reinterpret_cast<const EnumDescriptor*>(arg)->FindValueByNumber(
number) != nullptr;
return reinterpret_cast<const EnumDescriptor*>(arg)
->FindValueByNumber(number) != NULL;
}
bool DescriptorPoolExtensionFinder::Find(int number, ExtensionInfo* output) {
const FieldDescriptor* extension =
pool_->FindExtensionByNumber(containing_type_, number);
if (extension == nullptr) {
if (extension == NULL) {
return false;
} else {
output->type = extension->type();
@@ -310,10 +298,10 @@ bool DescriptorPoolExtensionFinder::Find(int number, ExtensionInfo* output) {
output->is_packed = extension->options().packed();
output->descriptor = extension;
if (extension->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
output->message_info.prototype =
output->message_prototype =
factory_->GetPrototype(extension->message_type());
GOOGLE_CHECK(output->message_info.prototype != nullptr)
<< "Extension factory's GetPrototype() returned nullptr; extension: "
GOOGLE_CHECK(output->message_prototype != NULL)
<< "Extension factory's GetPrototype() returned NULL for extension: "
<< extension->full_name();
} else if (extension->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
output->enum_validity_check.func = ValidateEnumUsingDescriptor;
@@ -324,63 +312,11 @@ bool DescriptorPoolExtensionFinder::Find(int number, ExtensionInfo* output) {
}
}
bool ExtensionSet::FindExtension(int wire_type, uint32_t field,
const Message* containing_type,
const internal::ParseContext* ctx,
ExtensionInfo* extension,
bool* was_packed_on_wire) {
if (ctx->data().pool == nullptr) {
GeneratedExtensionFinder finder(containing_type);
if (!FindExtensionInfoFromFieldNumber(wire_type, field, &finder, extension,
was_packed_on_wire)) {
return false;
}
} else {
DescriptorPoolExtensionFinder finder(ctx->data().pool, ctx->data().factory,
containing_type->GetDescriptor());
if (!FindExtensionInfoFromFieldNumber(wire_type, field, &finder, extension,
was_packed_on_wire)) {
return false;
}
}
return true;
}
const char* ExtensionSet::ParseField(uint64_t tag, const char* ptr,
const Message* containing_type,
internal::InternalMetadata* metadata,
internal::ParseContext* ctx) {
int number = tag >> 3;
bool was_packed_on_wire;
ExtensionInfo extension;
if (!FindExtension(tag & 7, number, containing_type, ctx, &extension,
&was_packed_on_wire)) {
return UnknownFieldParse(
tag, metadata->mutable_unknown_fields<UnknownFieldSet>(), ptr, ctx);
}
return ParseFieldWithExtensionInfo<UnknownFieldSet>(
number, was_packed_on_wire, extension, metadata, ptr, ctx);
}
const char* ExtensionSet::ParseFieldMaybeLazily(
uint64_t tag, const char* ptr, const Message* containing_type,
internal::InternalMetadata* metadata, internal::ParseContext* ctx) {
return ParseField(tag, ptr, containing_type, metadata, ctx);
}
const char* ExtensionSet::ParseMessageSetItem(
const char* ptr, const Message* containing_type,
internal::InternalMetadata* metadata, internal::ParseContext* ctx) {
return ParseMessageSetItemTmpl<Message, UnknownFieldSet>(ptr, containing_type,
metadata, ctx);
}
bool ExtensionSet::ParseField(uint32_t tag, io::CodedInputStream* input,
bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
const Message* containing_type,
UnknownFieldSet* unknown_fields) {
UnknownFieldSetFieldSkipper skipper(unknown_fields);
if (input->GetExtensionPool() == nullptr) {
if (input->GetExtensionPool() == NULL) {
GeneratedExtensionFinder finder(containing_type);
return ParseField(tag, input, &finder, &skipper);
} else {
@@ -395,7 +331,7 @@ bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
const Message* containing_type,
UnknownFieldSet* unknown_fields) {
MessageSetFieldSkipper skipper(unknown_fields);
if (input->GetExtensionPool() == nullptr) {
if (input->GetExtensionPool() == NULL) {
GeneratedExtensionFinder finder(containing_type);
return ParseMessageSet(input, &finder, &skipper);
} else {
@@ -411,10 +347,14 @@ int ExtensionSet::SpaceUsedExcludingSelf() const {
}
size_t ExtensionSet::SpaceUsedExcludingSelfLong() const {
size_t total_size = Size() * sizeof(KeyValue);
ForEach([&total_size](int /* number */, const Extension& ext) {
total_size += ext.SpaceUsedExcludingSelfLong();
});
size_t total_size =
extensions_.size() * sizeof(ExtensionMap::value_type);
for (ExtensionMap::const_iterator iter = extensions_.begin(),
end = extensions_.end();
iter != end;
++iter) {
total_size += iter->second.SpaceUsedExcludingSelfLong();
}
return total_size;
}
@@ -433,15 +373,15 @@ size_t ExtensionSet::Extension::SpaceUsedExcludingSelfLong() const {
repeated_##LOWERCASE##_value->SpaceUsedExcludingSelfLong(); \
break
HANDLE_TYPE(INT32, int32_t);
HANDLE_TYPE(INT64, int64_t);
HANDLE_TYPE(UINT32, uint32_t);
HANDLE_TYPE(UINT64, uint64_t);
HANDLE_TYPE(FLOAT, float);
HANDLE_TYPE(DOUBLE, double);
HANDLE_TYPE(BOOL, bool);
HANDLE_TYPE(ENUM, enum);
HANDLE_TYPE(STRING, string);
HANDLE_TYPE( INT32, int32);
HANDLE_TYPE( INT64, int64);
HANDLE_TYPE( UINT32, uint32);
HANDLE_TYPE( UINT64, uint64);
HANDLE_TYPE( FLOAT, float);
HANDLE_TYPE( DOUBLE, double);
HANDLE_TYPE( BOOL, bool);
HANDLE_TYPE( ENUM, enum);
HANDLE_TYPE( STRING, string);
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_MESSAGE:
@@ -449,10 +389,9 @@ size_t ExtensionSet::Extension::SpaceUsedExcludingSelfLong() const {
// but MessageLite has no SpaceUsedLong(), so we must directly call
// RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong() with a different
// type handler.
total_size += sizeof(*repeated_message_value) +
RepeatedMessage_SpaceUsedExcludingSelfLong(
reinterpret_cast<internal::RepeatedPtrFieldBase*>(
repeated_message_value));
total_size +=
sizeof(*repeated_message_value) +
RepeatedMessage_SpaceUsedExcludingSelfLong(repeated_message_value);
break;
}
} else {
@@ -476,29 +415,218 @@ size_t ExtensionSet::Extension::SpaceUsedExcludingSelfLong() const {
return total_size;
}
uint8_t* ExtensionSet::SerializeMessageSetWithCachedSizesToArray(
const MessageLite* extendee, uint8_t* target) const {
io::EpsCopyOutputStream stream(
target, MessageSetByteSize(),
io::CodedOutputStream::IsDefaultSerializationDeterministic());
return InternalSerializeMessageSetWithCachedSizesToArray(extendee, target,
&stream);
// The Serialize*ToArray methods are only needed in the heavy library, as
// the lite library only generates SerializeWithCachedSizes.
uint8* ExtensionSet::SerializeWithCachedSizesToArray(int start_field_number,
int end_field_number,
uint8* target) const {
return InternalSerializeWithCachedSizesToArray(
start_field_number, end_field_number,
google::protobuf::io::CodedOutputStream::IsDefaultSerializationDeterministic(),
target);
}
uint8* ExtensionSet::SerializeMessageSetWithCachedSizesToArray(
uint8* target) const {
return InternalSerializeMessageSetWithCachedSizesToArray(
google::protobuf::io::CodedOutputStream::IsDefaultSerializationDeterministic(),
target);
}
uint8* ExtensionSet::InternalSerializeWithCachedSizesToArray(
int start_field_number, int end_field_number,
bool deterministic, uint8* target) const {
ExtensionMap::const_iterator iter;
for (iter = extensions_.lower_bound(start_field_number);
iter != extensions_.end() && iter->first < end_field_number;
++iter) {
target = iter->second.InternalSerializeFieldWithCachedSizesToArray(
iter->first, deterministic, target);
}
return target;
}
uint8* ExtensionSet::InternalSerializeMessageSetWithCachedSizesToArray(
bool deterministic, uint8* target) const {
ExtensionMap::const_iterator iter;
for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) {
target = iter->second.InternalSerializeMessageSetItemWithCachedSizesToArray(
iter->first, deterministic, target);
}
return target;
}
uint8* ExtensionSet::Extension::InternalSerializeFieldWithCachedSizesToArray(
int number, bool deterministic, uint8* target) const {
if (is_repeated) {
if (is_packed) {
if (cached_size == 0) return target;
target = WireFormatLite::WriteTagToArray(number,
WireFormatLite::WIRETYPE_LENGTH_DELIMITED, target);
target = WireFormatLite::WriteInt32NoTagToArray(cached_size, target);
switch (real_type(type)) {
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \
case FieldDescriptor::TYPE_##UPPERCASE: \
for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
target = WireFormatLite::Write##CAMELCASE##NoTagToArray( \
repeated_##LOWERCASE##_value->Get(i), target); \
} \
break
HANDLE_TYPE( INT32, Int32, int32);
HANDLE_TYPE( INT64, Int64, int64);
HANDLE_TYPE( UINT32, UInt32, uint32);
HANDLE_TYPE( UINT64, UInt64, uint64);
HANDLE_TYPE( SINT32, SInt32, int32);
HANDLE_TYPE( SINT64, SInt64, int64);
HANDLE_TYPE( FIXED32, Fixed32, uint32);
HANDLE_TYPE( FIXED64, Fixed64, uint64);
HANDLE_TYPE(SFIXED32, SFixed32, int32);
HANDLE_TYPE(SFIXED64, SFixed64, int64);
HANDLE_TYPE( FLOAT, Float, float);
HANDLE_TYPE( DOUBLE, Double, double);
HANDLE_TYPE( BOOL, Bool, bool);
HANDLE_TYPE( ENUM, Enum, enum);
#undef HANDLE_TYPE
case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES:
case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_MESSAGE:
GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
break;
}
} else {
switch (real_type(type)) {
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \
case FieldDescriptor::TYPE_##UPPERCASE: \
for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
target = WireFormatLite::Write##CAMELCASE##ToArray(number, \
repeated_##LOWERCASE##_value->Get(i), target); \
} \
break
HANDLE_TYPE( INT32, Int32, int32);
HANDLE_TYPE( INT64, Int64, int64);
HANDLE_TYPE( UINT32, UInt32, uint32);
HANDLE_TYPE( UINT64, UInt64, uint64);
HANDLE_TYPE( SINT32, SInt32, int32);
HANDLE_TYPE( SINT64, SInt64, int64);
HANDLE_TYPE( FIXED32, Fixed32, uint32);
HANDLE_TYPE( FIXED64, Fixed64, uint64);
HANDLE_TYPE(SFIXED32, SFixed32, int32);
HANDLE_TYPE(SFIXED64, SFixed64, int64);
HANDLE_TYPE( FLOAT, Float, float);
HANDLE_TYPE( DOUBLE, Double, double);
HANDLE_TYPE( BOOL, Bool, bool);
HANDLE_TYPE( STRING, String, string);
HANDLE_TYPE( BYTES, Bytes, string);
HANDLE_TYPE( ENUM, Enum, enum);
#undef HANDLE_TYPE
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \
case FieldDescriptor::TYPE_##UPPERCASE: \
for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
target = WireFormatLite::InternalWrite##CAMELCASE##ToArray( \
number, repeated_##LOWERCASE##_value->Get(i), \
deterministic, target); \
} \
break
HANDLE_TYPE( GROUP, Group, message);
HANDLE_TYPE( MESSAGE, Message, message);
#undef HANDLE_TYPE
}
}
} else if (!is_cleared) {
switch (real_type(type)) {
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE) \
case FieldDescriptor::TYPE_##UPPERCASE: \
target = WireFormatLite::Write##CAMELCASE##ToArray( \
number, VALUE, target); \
break
HANDLE_TYPE( INT32, Int32, int32_value);
HANDLE_TYPE( INT64, Int64, int64_value);
HANDLE_TYPE( UINT32, UInt32, uint32_value);
HANDLE_TYPE( UINT64, UInt64, uint64_value);
HANDLE_TYPE( SINT32, SInt32, int32_value);
HANDLE_TYPE( SINT64, SInt64, int64_value);
HANDLE_TYPE( FIXED32, Fixed32, uint32_value);
HANDLE_TYPE( FIXED64, Fixed64, uint64_value);
HANDLE_TYPE(SFIXED32, SFixed32, int32_value);
HANDLE_TYPE(SFIXED64, SFixed64, int64_value);
HANDLE_TYPE( FLOAT, Float, float_value);
HANDLE_TYPE( DOUBLE, Double, double_value);
HANDLE_TYPE( BOOL, Bool, bool_value);
HANDLE_TYPE( STRING, String, *string_value);
HANDLE_TYPE( BYTES, Bytes, *string_value);
HANDLE_TYPE( ENUM, Enum, enum_value);
HANDLE_TYPE( GROUP, Group, *message_value);
#undef HANDLE_TYPE
case FieldDescriptor::TYPE_MESSAGE:
if (is_lazy) {
target = lazymessage_value->InternalWriteMessageToArray(
number, deterministic, target);
} else {
target = WireFormatLite::InternalWriteMessageToArray(
number, *message_value, deterministic, target);
}
break;
}
}
return target;
}
uint8*
ExtensionSet::Extension::InternalSerializeMessageSetItemWithCachedSizesToArray(
int number, bool deterministic, uint8* target) const {
if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
// Not a valid MessageSet extension, but serialize it the normal way.
GOOGLE_LOG(WARNING) << "Invalid message set extension.";
return InternalSerializeFieldWithCachedSizesToArray(number, deterministic,
target);
}
if (is_cleared) return target;
// Start group.
target = io::CodedOutputStream::WriteTagToArray(
WireFormatLite::kMessageSetItemStartTag, target);
// Write type ID.
target = WireFormatLite::WriteUInt32ToArray(
WireFormatLite::kMessageSetTypeIdNumber, number, target);
// Write message.
if (is_lazy) {
target = lazymessage_value->InternalWriteMessageToArray(
WireFormatLite::kMessageSetMessageNumber, deterministic, target);
} else {
target = WireFormatLite::InternalWriteMessageToArray(
WireFormatLite::kMessageSetMessageNumber, *message_value, deterministic,
target);
}
// End group.
target = io::CodedOutputStream::WriteTagToArray(
WireFormatLite::kMessageSetItemEndTag, target);
return target;
}
bool ExtensionSet::ParseFieldMaybeLazily(
int wire_type, int field_number, io::CodedInputStream* input,
ExtensionFinder* extension_finder, MessageSetFieldSkipper* field_skipper) {
return ParseField(
WireFormatLite::MakeTag(field_number,
static_cast<WireFormatLite::WireType>(wire_type)),
input, extension_finder, field_skipper);
ExtensionFinder* extension_finder,
MessageSetFieldSkipper* field_skipper) {
return ParseField(WireFormatLite::MakeTag(
field_number, static_cast<WireFormatLite::WireType>(wire_type)),
input, extension_finder, field_skipper);
}
bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
ExtensionFinder* extension_finder,
MessageSetFieldSkipper* field_skipper) {
while (true) {
const uint32_t tag = input->ReadTag();
const uint32 tag = input->ReadTag();
switch (tag) {
case 0:
return true;
@@ -516,31 +644,171 @@ bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
}
}
bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
const MessageLite* containing_type) {
MessageSetFieldSkipper skipper(NULL);
GeneratedExtensionFinder finder(containing_type);
return ParseMessageSet(input, &finder, &skipper);
}
bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input,
ExtensionFinder* extension_finder,
MessageSetFieldSkipper* field_skipper) {
struct MSFull {
bool ParseField(int type_id, io::CodedInputStream* input) {
return me->ParseFieldMaybeLazily(
WireFormatLite::WIRETYPE_LENGTH_DELIMITED, type_id, input,
extension_finder, field_skipper);
// TODO(kenton): It would be nice to share code between this and
// WireFormatLite::ParseAndMergeMessageSetItem(), but I think the
// differences would be hard to factor out.
// This method parses a group which should contain two fields:
// required int32 type_id = 2;
// required data message = 3;
uint32 last_type_id = 0;
// If we see message data before the type_id, we'll append it to this so
// we can parse it later.
string message_data;
while (true) {
const uint32 tag = input->ReadTagNoLastTag();
if (tag == 0) return false;
switch (tag) {
case WireFormatLite::kMessageSetTypeIdTag: {
uint32 type_id;
if (!input->ReadVarint32(&type_id)) return false;
last_type_id = type_id;
if (!message_data.empty()) {
// We saw some message data before the type_id. Have to parse it
// now.
io::CodedInputStream sub_input(
reinterpret_cast<const uint8*>(message_data.data()),
message_data.size());
if (!ParseFieldMaybeLazily(WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
last_type_id, &sub_input,
extension_finder, field_skipper)) {
return false;
}
message_data.clear();
}
break;
}
case WireFormatLite::kMessageSetMessageTag: {
if (last_type_id == 0) {
// We haven't seen a type_id yet. Append this data to message_data.
string temp;
uint32 length;
if (!input->ReadVarint32(&length)) return false;
if (!input->ReadString(&temp, length)) return false;
io::StringOutputStream output_stream(&message_data);
io::CodedOutputStream coded_output(&output_stream);
coded_output.WriteVarint32(length);
coded_output.WriteString(temp);
} else {
// Already saw type_id, so we can parse this directly.
if (!ParseFieldMaybeLazily(WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
last_type_id, input,
extension_finder, field_skipper)) {
return false;
}
}
break;
}
case WireFormatLite::kMessageSetItemEndTag: {
return true;
}
default: {
if (!field_skipper->SkipField(input, tag)) return false;
}
}
}
}
bool SkipField(uint32_t tag, io::CodedInputStream* input) {
return field_skipper->SkipField(input, tag);
}
void ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizes(
int number,
io::CodedOutputStream* output) const {
if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
// Not a valid MessageSet extension, but serialize it the normal way.
SerializeFieldWithCachedSizes(number, output);
return;
}
ExtensionSet* me;
ExtensionFinder* extension_finder;
MessageSetFieldSkipper* field_skipper;
};
if (is_cleared) return;
return ParseMessageSetItemImpl(input,
MSFull{this, extension_finder, field_skipper});
// Start group.
output->WriteTag(WireFormatLite::kMessageSetItemStartTag);
// Write type ID.
WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber,
number,
output);
// Write message.
if (is_lazy) {
lazymessage_value->WriteMessage(
WireFormatLite::kMessageSetMessageNumber, output);
} else {
WireFormatLite::WriteMessageMaybeToArray(
WireFormatLite::kMessageSetMessageNumber,
*message_value,
output);
}
// End group.
output->WriteTag(WireFormatLite::kMessageSetItemEndTag);
}
size_t ExtensionSet::Extension::MessageSetItemByteSize(int number) const {
if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
// Not a valid MessageSet extension, but compute the byte size for it the
// normal way.
return ByteSize(number);
}
if (is_cleared) return 0;
size_t our_size = WireFormatLite::kMessageSetItemTagsSize;
// type_id
our_size += io::CodedOutputStream::VarintSize32(number);
// message
size_t message_size = 0;
if (is_lazy) {
message_size = lazymessage_value->ByteSize();
} else {
message_size = message_value->ByteSize();
}
our_size += io::CodedOutputStream::VarintSize32(message_size);
our_size += message_size;
return our_size;
}
void ExtensionSet::SerializeMessageSetWithCachedSizes(
io::CodedOutputStream* output) const {
for (ExtensionMap::const_iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
iter->second.SerializeMessageSetItemWithCachedSizes(iter->first, output);
}
}
size_t ExtensionSet::MessageSetByteSize() const {
size_t total_size = 0;
for (ExtensionMap::const_iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
total_size += iter->second.MessageSetItemByteSize(iter->first);
}
return total_size;
}
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
@@ -1,276 +0,0 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
#define GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
#include <google/protobuf/parse_context.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/metadata_lite.h>
namespace google {
namespace protobuf {
namespace internal {
template <typename T>
const char* ExtensionSet::ParseFieldWithExtensionInfo(
int number, bool was_packed_on_wire, const ExtensionInfo& extension,
InternalMetadata* metadata, const char* ptr, internal::ParseContext* ctx) {
if (was_packed_on_wire) {
switch (extension.type) {
#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE) \
case WireFormatLite::TYPE_##UPPERCASE: \
return internal::Packed##CPP_CAMELCASE##Parser( \
MutableRawRepeatedField(number, extension.type, extension.is_packed, \
extension.descriptor), \
ptr, ctx);
HANDLE_TYPE(INT32, Int32);
HANDLE_TYPE(INT64, Int64);
HANDLE_TYPE(UINT32, UInt32);
HANDLE_TYPE(UINT64, UInt64);
HANDLE_TYPE(SINT32, SInt32);
HANDLE_TYPE(SINT64, SInt64);
HANDLE_TYPE(FIXED32, Fixed32);
HANDLE_TYPE(FIXED64, Fixed64);
HANDLE_TYPE(SFIXED32, SFixed32);
HANDLE_TYPE(SFIXED64, SFixed64);
HANDLE_TYPE(FLOAT, Float);
HANDLE_TYPE(DOUBLE, Double);
HANDLE_TYPE(BOOL, Bool);
#undef HANDLE_TYPE
case WireFormatLite::TYPE_ENUM:
return internal::PackedEnumParserArg<T>(
MutableRawRepeatedField(number, extension.type, extension.is_packed,
extension.descriptor),
ptr, ctx, extension.enum_validity_check.func,
extension.enum_validity_check.arg, metadata, number);
case WireFormatLite::TYPE_STRING:
case WireFormatLite::TYPE_BYTES:
case WireFormatLite::TYPE_GROUP:
case WireFormatLite::TYPE_MESSAGE:
GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
break;
}
} else {
switch (extension.type) {
#define HANDLE_VARINT_TYPE(UPPERCASE, CPP_CAMELCASE) \
case WireFormatLite::TYPE_##UPPERCASE: { \
uint64_t value; \
ptr = VarintParse(ptr, &value); \
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); \
if (extension.is_repeated) { \
Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \
extension.is_packed, value, extension.descriptor); \
} else { \
Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \
extension.descriptor); \
} \
} break
HANDLE_VARINT_TYPE(INT32, Int32);
HANDLE_VARINT_TYPE(INT64, Int64);
HANDLE_VARINT_TYPE(UINT32, UInt32);
HANDLE_VARINT_TYPE(UINT64, UInt64);
HANDLE_VARINT_TYPE(BOOL, Bool);
#undef HANDLE_VARINT_TYPE
#define HANDLE_SVARINT_TYPE(UPPERCASE, CPP_CAMELCASE, SIZE) \
case WireFormatLite::TYPE_##UPPERCASE: { \
uint64_t val; \
ptr = VarintParse(ptr, &val); \
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); \
auto value = WireFormatLite::ZigZagDecode##SIZE(val); \
if (extension.is_repeated) { \
Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \
extension.is_packed, value, extension.descriptor); \
} else { \
Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \
extension.descriptor); \
} \
} break
HANDLE_SVARINT_TYPE(SINT32, Int32, 32);
HANDLE_SVARINT_TYPE(SINT64, Int64, 64);
#undef HANDLE_SVARINT_TYPE
#define HANDLE_FIXED_TYPE(UPPERCASE, CPP_CAMELCASE, CPPTYPE) \
case WireFormatLite::TYPE_##UPPERCASE: { \
auto value = UnalignedLoad<CPPTYPE>(ptr); \
ptr += sizeof(CPPTYPE); \
if (extension.is_repeated) { \
Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \
extension.is_packed, value, extension.descriptor); \
} else { \
Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \
extension.descriptor); \
} \
} break
HANDLE_FIXED_TYPE(FIXED32, UInt32, uint32_t);
HANDLE_FIXED_TYPE(FIXED64, UInt64, uint64_t);
HANDLE_FIXED_TYPE(SFIXED32, Int32, int32_t);
HANDLE_FIXED_TYPE(SFIXED64, Int64, int64_t);
HANDLE_FIXED_TYPE(FLOAT, Float, float);
HANDLE_FIXED_TYPE(DOUBLE, Double, double);
#undef HANDLE_FIXED_TYPE
case WireFormatLite::TYPE_ENUM: {
uint64_t val;
ptr = VarintParse(ptr, &val);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
int value = val;
if (!extension.enum_validity_check.func(
extension.enum_validity_check.arg, value)) {
WriteVarint(number, val, metadata->mutable_unknown_fields<T>());
} else if (extension.is_repeated) {
AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, value,
extension.descriptor);
} else {
SetEnum(number, WireFormatLite::TYPE_ENUM, value,
extension.descriptor);
}
break;
}
case WireFormatLite::TYPE_BYTES:
case WireFormatLite::TYPE_STRING: {
std::string* value =
extension.is_repeated
? AddString(number, WireFormatLite::TYPE_STRING,
extension.descriptor)
: MutableString(number, WireFormatLite::TYPE_STRING,
extension.descriptor);
int size = ReadSize(&ptr);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
return ctx->ReadString(ptr, size, value);
}
case WireFormatLite::TYPE_GROUP: {
MessageLite* value =
extension.is_repeated
? AddMessage(number, WireFormatLite::TYPE_GROUP,
*extension.message_info.prototype,
extension.descriptor)
: MutableMessage(number, WireFormatLite::TYPE_GROUP,
*extension.message_info.prototype,
extension.descriptor);
uint32_t tag = (number << 3) + WireFormatLite::WIRETYPE_START_GROUP;
return ctx->ParseGroup(value, ptr, tag);
}
case WireFormatLite::TYPE_MESSAGE: {
MessageLite* value =
extension.is_repeated
? AddMessage(number, WireFormatLite::TYPE_MESSAGE,
*extension.message_info.prototype,
extension.descriptor)
: MutableMessage(number, WireFormatLite::TYPE_MESSAGE,
*extension.message_info.prototype,
extension.descriptor);
return ctx->ParseMessage(value, ptr);
}
}
}
return ptr;
}
template <typename Msg, typename T>
const char* ExtensionSet::ParseMessageSetItemTmpl(
const char* ptr, const Msg* extendee, internal::InternalMetadata* metadata,
internal::ParseContext* ctx) {
std::string payload;
uint32_t type_id = 0;
bool payload_read = false;
while (!ctx->Done(&ptr)) {
uint32_t tag = static_cast<uint8_t>(*ptr++);
if (tag == WireFormatLite::kMessageSetTypeIdTag) {
uint64_t tmp;
ptr = ParseBigVarint(ptr, &tmp);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
type_id = tmp;
if (payload_read) {
ExtensionInfo extension;
bool was_packed_on_wire;
if (!FindExtension(2, type_id, extendee, ctx, &extension,
&was_packed_on_wire)) {
WriteLengthDelimited(type_id, payload,
metadata->mutable_unknown_fields<T>());
} else {
MessageLite* value =
extension.is_repeated
? AddMessage(type_id, WireFormatLite::TYPE_MESSAGE,
*extension.message_info.prototype,
extension.descriptor)
: MutableMessage(type_id, WireFormatLite::TYPE_MESSAGE,
*extension.message_info.prototype,
extension.descriptor);
const char* p;
// We can't use regular parse from string as we have to track
// proper recursion depth and descriptor pools.
ParseContext tmp_ctx(ctx->depth(), false, &p, payload);
tmp_ctx.data().pool = ctx->data().pool;
tmp_ctx.data().factory = ctx->data().factory;
GOOGLE_PROTOBUF_PARSER_ASSERT(value->_InternalParse(p, &tmp_ctx) &&
tmp_ctx.EndedAtLimit());
}
type_id = 0;
}
} else if (tag == WireFormatLite::kMessageSetMessageTag) {
if (type_id != 0) {
ptr = ParseFieldMaybeLazily(static_cast<uint64_t>(type_id) * 8 + 2, ptr,
extendee, metadata, ctx);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
type_id = 0;
} else {
int32_t size = ReadSize(&ptr);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
ptr = ctx->ReadString(ptr, size, &payload);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
payload_read = true;
}
} else {
ptr = ReadTag(ptr - 1, &tag);
if (tag == 0 || (tag & 7) == 4) {
ctx->SetLastTag(tag);
return ptr;
}
ptr = ParseField(tag, ptr, extendee, metadata, ctx);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
}
}
return ptr;
}
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
@@ -1,172 +0,0 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_PROTOBUF_FIELD_ACCESS_LISTENER_H__
#define GOOGLE_PROTOBUF_FIELD_ACCESS_LISTENER_H__
#include <cstddef>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/message_lite.h>
namespace google {
namespace protobuf {
// A default/no-op implementation of message hooks.
//
// See go/statically-dispatched-message-hooks for details.
template <typename Proto>
struct NoOpAccessListener {
// Number of fields are provided at compile time for the trackers to be able
// to have stack allocated bitmaps for the fields. This is useful for
// performance critical trackers. This is also to avoid cyclic dependencies
// if the number of fields is needed.
static constexpr int kFields = Proto::_kInternalFieldNumber;
// Default constructor is called during the static global initialization of
// the program.
// We provide a pointer to extract the name of the proto not to get cyclic
// dependencies on GetDescriptor() and OnGetMetadata() calls. If you want
// to differentiate the protos during the runtime before the start of the
// program, use this functor to get its name. We either way need it for
// LITE_RUNTIME protos as they don't have descriptors at all.
explicit NoOpAccessListener(StringPiece (*name_extractor)()) {}
// called repeatedly during serialization/deserialization/ByteSize of
// Reflection as:
// AccessListener<MessageT>::OnSerialize(this);
static void OnSerialize(const MessageLite* msg) {}
static void OnDeserialize(const MessageLite* msg) {}
static void OnByteSize(const MessageLite* msg) {}
static void OnMergeFrom(const MessageLite* to, const MessageLite* from) {}
// NOTE: This function can be called pre-main. Make sure it does not make
// the state of the listener invalid.
static void OnGetMetadata() {}
// called from accessors as:
// AccessListener<MessageT>::On$operation(this, &field_storage_);
// If you need to override this with type, in your hook implementation
// introduce
// template <int kFieldNum, typename T>
// static void On$operation(const MessageLite* msg,
// const T* field) {}
// And overloads for std::nullptr_t for incomplete types such as Messages,
// Maps. Extract them using reflection if you need. Consequently, second
// argument can be null pointer.
// For an example, see proto_hooks/testing/memory_test_field_listener.h
// And argument template deduction will deduce the type itself without
// changing the generated code.
// add_<field>(f)
template <int kFieldNum>
static void OnAdd(const MessageLite* msg, const void* field) {}
// add_<field>()
template <int kFieldNum>
static void OnAddMutable(const MessageLite* msg, const void* field) {}
// <field>() and <repeated_field>(i)
template <int kFieldNum>
static void OnGet(const MessageLite* msg, const void* field) {}
// clear_<field>()
template <int kFieldNum>
static void OnClear(const MessageLite* msg, const void* field) {}
// has_<field>()
template <int kFieldNum>
static void OnHas(const MessageLite* msg, const void* field) {}
// <repeated_field>()
template <int kFieldNum>
static void OnList(const MessageLite* msg, const void* field) {}
// mutable_<field>()
template <int kFieldNum>
static void OnMutable(const MessageLite* msg, const void* field) {}
// mutable_<repeated_field>()
template <int kFieldNum>
static void OnMutableList(const MessageLite* msg, const void* field) {}
// release_<field>()
template <int kFieldNum>
static void OnRelease(const MessageLite* msg, const void* field) {}
// set_<field>() and set_<repeated_field>(i)
template <int kFieldNum>
static void OnSet(const MessageLite* msg, const void* field) {}
// <repeated_field>_size()
template <int kFieldNum>
static void OnSize(const MessageLite* msg, const void* field) {}
static void OnHasExtension(const MessageLite* msg, int extension_tag,
const void* field) {}
// TODO(b/190614678): Support clear in the proto compiler.
static void OnClearExtension(const MessageLite* msg, int extension_tag,
const void* field) {}
static void OnExtensionSize(const MessageLite* msg, int extension_tag,
const void* field) {}
static void OnGetExtension(const MessageLite* msg, int extension_tag,
const void* field) {}
static void OnMutableExtension(const MessageLite* msg, int extension_tag,
const void* field) {}
static void OnSetExtension(const MessageLite* msg, int extension_tag,
const void* field) {}
static void OnReleaseExtension(const MessageLite* msg, int extension_tag,
const void* field) {}
static void OnAddExtension(const MessageLite* msg, int extension_tag,
const void* field) {}
static void OnAddMutableExtension(const MessageLite* msg, int extension_tag,
const void* field) {}
static void OnListExtension(const MessageLite* msg, int extension_tag,
const void* field) {}
static void OnMutableListExtension(const MessageLite* msg, int extension_tag,
const void* field) {}
};
} // namespace protobuf
} // namespace google
#ifndef REPLACE_PROTO_LISTENER_IMPL
namespace google {
namespace protobuf {
template <class T>
using AccessListener = NoOpAccessListener<T>;
} // namespace protobuf
} // namespace google
#else
// You can put your implementations of hooks/listeners here.
// All hooks are subject to approval by protobuf-team@.
#endif // !REPLACE_PROTO_LISTENER_IMPL
#endif // GOOGLE_PROTOBUF_FIELD_ACCESS_LISTENER_H__
+373
View File
@@ -0,0 +1,373 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/protobuf/field_mask.proto
#include <google/protobuf/field_mask.pb.h>
#include <algorithm>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/wire_format.h>
// This is a temporary google only hack
#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
#include "third_party/protobuf/version.h"
#endif
// @@protoc_insertion_point(includes)
namespace google {
namespace protobuf {
class FieldMaskDefaultTypeInternal {
public:
::google::protobuf::internal::ExplicitlyConstructed<FieldMask>
_instance;
} _FieldMask_default_instance_;
} // namespace protobuf
} // namespace google
namespace protobuf_google_2fprotobuf_2ffield_5fmask_2eproto {
void InitDefaultsFieldMaskImpl() {
GOOGLE_PROTOBUF_VERIFY_VERSION;
#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
::google::protobuf::internal::InitProtobufDefaultsForceUnique();
#else
::google::protobuf::internal::InitProtobufDefaults();
#endif // GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
{
void* ptr = &::google::protobuf::_FieldMask_default_instance_;
new (ptr) ::google::protobuf::FieldMask();
::google::protobuf::internal::OnShutdownDestroyMessage(ptr);
}
::google::protobuf::FieldMask::InitAsDefaultInstance();
}
void InitDefaultsFieldMask() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &InitDefaultsFieldMaskImpl);
}
::google::protobuf::Metadata file_level_metadata[1];
const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
~0u, // no _has_bits_
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::FieldMask, _internal_metadata_),
~0u, // no _extensions_
~0u, // no _oneof_case_
~0u, // no _weak_field_map_
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::google::protobuf::FieldMask, paths_),
};
static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
{ 0, -1, sizeof(::google::protobuf::FieldMask)},
};
static ::google::protobuf::Message const * const file_default_instances[] = {
reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::_FieldMask_default_instance_),
};
void protobuf_AssignDescriptors() {
AddDescriptors();
::google::protobuf::MessageFactory* factory = NULL;
AssignDescriptors(
"google/protobuf/field_mask.proto", schemas, file_default_instances, TableStruct::offsets, factory,
file_level_metadata, NULL, NULL);
}
void protobuf_AssignDescriptorsOnce() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors);
}
void protobuf_RegisterTypes(const ::std::string&) GOOGLE_PROTOBUF_ATTRIBUTE_COLD;
void protobuf_RegisterTypes(const ::std::string&) {
protobuf_AssignDescriptorsOnce();
::google::protobuf::internal::RegisterAllTypes(file_level_metadata, 1);
}
void AddDescriptorsImpl() {
InitDefaults();
static const char descriptor[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
"\n google/protobuf/field_mask.proto\022\017goog"
"le.protobuf\"\032\n\tFieldMask\022\r\n\005paths\030\001 \003(\tB"
"\211\001\n\023com.google.protobufB\016FieldMaskProtoP"
"\001Z9google.golang.org/genproto/protobuf/f"
"ield_mask;field_mask\242\002\003GPB\252\002\036Google.Prot"
"obuf.WellKnownTypesb\006proto3"
};
::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
descriptor, 227);
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
"google/protobuf/field_mask.proto", &protobuf_RegisterTypes);
}
void AddDescriptors() {
static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);
}
// Force AddDescriptors() to be called at dynamic initialization time.
struct StaticDescriptorInitializer {
StaticDescriptorInitializer() {
AddDescriptors();
}
} static_descriptor_initializer;
} // namespace protobuf_google_2fprotobuf_2ffield_5fmask_2eproto
namespace google {
namespace protobuf {
// ===================================================================
void FieldMask::InitAsDefaultInstance() {
}
#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int FieldMask::kPathsFieldNumber;
#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
FieldMask::FieldMask()
: ::google::protobuf::Message(), _internal_metadata_(NULL) {
if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
::protobuf_google_2fprotobuf_2ffield_5fmask_2eproto::InitDefaultsFieldMask();
}
SharedCtor();
// @@protoc_insertion_point(constructor:google.protobuf.FieldMask)
}
FieldMask::FieldMask(const FieldMask& from)
: ::google::protobuf::Message(),
_internal_metadata_(NULL),
paths_(from.paths_),
_cached_size_(0) {
_internal_metadata_.MergeFrom(from._internal_metadata_);
// @@protoc_insertion_point(copy_constructor:google.protobuf.FieldMask)
}
void FieldMask::SharedCtor() {
_cached_size_ = 0;
}
FieldMask::~FieldMask() {
// @@protoc_insertion_point(destructor:google.protobuf.FieldMask)
SharedDtor();
}
void FieldMask::SharedDtor() {
}
void FieldMask::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
}
const ::google::protobuf::Descriptor* FieldMask::descriptor() {
::protobuf_google_2fprotobuf_2ffield_5fmask_2eproto::protobuf_AssignDescriptorsOnce();
return ::protobuf_google_2fprotobuf_2ffield_5fmask_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
}
const FieldMask& FieldMask::default_instance() {
::protobuf_google_2fprotobuf_2ffield_5fmask_2eproto::InitDefaultsFieldMask();
return *internal_default_instance();
}
FieldMask* FieldMask::New(::google::protobuf::Arena* arena) const {
FieldMask* n = new FieldMask;
if (arena != NULL) {
arena->Own(n);
}
return n;
}
void FieldMask::Clear() {
// @@protoc_insertion_point(message_clear_start:google.protobuf.FieldMask)
::google::protobuf::uint32 cached_has_bits = 0;
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
paths_.Clear();
_internal_metadata_.Clear();
}
bool FieldMask::MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) {
#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
::google::protobuf::uint32 tag;
// @@protoc_insertion_point(parse_start:google.protobuf.FieldMask)
for (;;) {
::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
tag = p.first;
if (!p.second) goto handle_unusual;
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// repeated string paths = 1;
case 1: {
if (static_cast< ::google::protobuf::uint8>(tag) ==
static_cast< ::google::protobuf::uint8>(10u /* 10 & 0xFF */)) {
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->add_paths()));
DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
this->paths(this->paths_size() - 1).data(),
static_cast<int>(this->paths(this->paths_size() - 1).length()),
::google::protobuf::internal::WireFormatLite::PARSE,
"google.protobuf.FieldMask.paths"));
} else {
goto handle_unusual;
}
break;
}
default: {
handle_unusual:
if (tag == 0) {
goto success;
}
DO_(::google::protobuf::internal::WireFormat::SkipField(
input, tag, _internal_metadata_.mutable_unknown_fields()));
break;
}
}
}
success:
// @@protoc_insertion_point(parse_success:google.protobuf.FieldMask)
return true;
failure:
// @@protoc_insertion_point(parse_failure:google.protobuf.FieldMask)
return false;
#undef DO_
}
void FieldMask::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
// @@protoc_insertion_point(serialize_start:google.protobuf.FieldMask)
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
// repeated string paths = 1;
for (int i = 0, n = this->paths_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
this->paths(i).data(), static_cast<int>(this->paths(i).length()),
::google::protobuf::internal::WireFormatLite::SERIALIZE,
"google.protobuf.FieldMask.paths");
::google::protobuf::internal::WireFormatLite::WriteString(
1, this->paths(i), output);
}
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), output);
}
// @@protoc_insertion_point(serialize_end:google.protobuf.FieldMask)
}
::google::protobuf::uint8* FieldMask::InternalSerializeWithCachedSizesToArray(
bool deterministic, ::google::protobuf::uint8* target) const {
(void)deterministic; // Unused
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldMask)
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
// repeated string paths = 1;
for (int i = 0, n = this->paths_size(); i < n; i++) {
::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
this->paths(i).data(), static_cast<int>(this->paths(i).length()),
::google::protobuf::internal::WireFormatLite::SERIALIZE,
"google.protobuf.FieldMask.paths");
target = ::google::protobuf::internal::WireFormatLite::
WriteStringToArray(1, this->paths(i), target);
}
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), target);
}
// @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FieldMask)
return target;
}
size_t FieldMask::ByteSizeLong() const {
// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldMask)
size_t total_size = 0;
if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
total_size +=
::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
(::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()));
}
// repeated string paths = 1;
total_size += 1 *
::google::protobuf::internal::FromIntSize(this->paths_size());
for (int i = 0, n = this->paths_size(); i < n; i++) {
total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
this->paths(i));
}
int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = cached_size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
return total_size;
}
void FieldMask::MergeFrom(const ::google::protobuf::Message& from) {
// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FieldMask)
GOOGLE_DCHECK_NE(&from, this);
const FieldMask* source =
::google::protobuf::internal::DynamicCastToGenerated<const FieldMask>(
&from);
if (source == NULL) {
// @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FieldMask)
::google::protobuf::internal::ReflectionOps::Merge(from, this);
} else {
// @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FieldMask)
MergeFrom(*source);
}
}
void FieldMask::MergeFrom(const FieldMask& from) {
// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldMask)
GOOGLE_DCHECK_NE(&from, this);
_internal_metadata_.MergeFrom(from._internal_metadata_);
::google::protobuf::uint32 cached_has_bits = 0;
(void) cached_has_bits;
paths_.MergeFrom(from.paths_);
}
void FieldMask::CopyFrom(const ::google::protobuf::Message& from) {
// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FieldMask)
if (&from == this) return;
Clear();
MergeFrom(from);
}
void FieldMask::CopyFrom(const FieldMask& from) {
// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FieldMask)
if (&from == this) return;
Clear();
MergeFrom(from);
}
bool FieldMask::IsInitialized() const {
return true;
}
void FieldMask::Swap(FieldMask* other) {
if (other == this) return;
InternalSwap(other);
}
void FieldMask::InternalSwap(FieldMask* other) {
using std::swap;
paths_.InternalSwap(&other->paths_);
_internal_metadata_.Swap(&other->_internal_metadata_);
swap(_cached_size_, other->_cached_size_);
}
::google::protobuf::Metadata FieldMask::GetMetadata() const {
protobuf_google_2fprotobuf_2ffield_5fmask_2eproto::protobuf_AssignDescriptorsOnce();
return ::protobuf_google_2fprotobuf_2ffield_5fmask_2eproto::file_level_metadata[kIndexInFileMessages];
}
// @@protoc_insertion_point(namespace_scope)
} // namespace protobuf
} // namespace google
// @@protoc_insertion_point(global_scope)
+113 -170
View File
@@ -1,228 +1,177 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/protobuf/field_mask.proto
#ifndef GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ffield_5fmask_2eproto
#define GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ffield_5fmask_2eproto
#ifndef PROTOBUF_google_2fprotobuf_2ffield_5fmask_2eproto__INCLUDED
#define PROTOBUF_google_2fprotobuf_2ffield_5fmask_2eproto__INCLUDED
#include <limits>
#include <string>
#include <google/protobuf/port_def.inc>
#if PROTOBUF_VERSION < 3019000
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3005000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3019001 < PROTOBUF_MIN_PROTOC_VERSION
#if 3005001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
#endif
#include <google/protobuf/port_undef.inc>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/metadata_lite.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/metadata.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h> // IWYU pragma: export
#include <google/protobuf/extension_set.h> // IWYU pragma: export
#include <google/protobuf/unknown_field_set.h>
// @@protoc_insertion_point(includes)
#include <google/protobuf/port_def.inc>
#define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2ffield_5fmask_2eproto PROTOBUF_EXPORT
PROTOBUF_NAMESPACE_OPEN
namespace internal {
class AnyMetadata;
} // namespace internal
PROTOBUF_NAMESPACE_CLOSE
namespace protobuf_google_2fprotobuf_2ffield_5fmask_2eproto {
// Internal implementation detail -- do not use these members.
struct PROTOBUF_EXPORT TableStruct_google_2fprotobuf_2ffield_5fmask_2eproto {
static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[]
PROTOBUF_SECTION_VARIABLE(protodesc_cold);
static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[]
PROTOBUF_SECTION_VARIABLE(protodesc_cold);
static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[1]
PROTOBUF_SECTION_VARIABLE(protodesc_cold);
static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[];
static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[];
static const uint32_t offsets[];
struct LIBPROTOBUF_EXPORT TableStruct {
static const ::google::protobuf::internal::ParseTableField entries[];
static const ::google::protobuf::internal::AuxillaryParseTableField aux[];
static const ::google::protobuf::internal::ParseTable schema[1];
static const ::google::protobuf::internal::FieldMetadata field_metadata[];
static const ::google::protobuf::internal::SerializationTable serialization_table[];
static const ::google::protobuf::uint32 offsets[];
};
PROTOBUF_EXPORT extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto;
PROTOBUF_NAMESPACE_OPEN
void LIBPROTOBUF_EXPORT AddDescriptors();
void LIBPROTOBUF_EXPORT InitDefaultsFieldMaskImpl();
void LIBPROTOBUF_EXPORT InitDefaultsFieldMask();
inline void LIBPROTOBUF_EXPORT InitDefaults() {
InitDefaultsFieldMask();
}
} // namespace protobuf_google_2fprotobuf_2ffield_5fmask_2eproto
namespace google {
namespace protobuf {
class FieldMask;
struct FieldMaskDefaultTypeInternal;
PROTOBUF_EXPORT extern FieldMaskDefaultTypeInternal _FieldMask_default_instance_;
PROTOBUF_NAMESPACE_CLOSE
PROTOBUF_NAMESPACE_OPEN
template<> PROTOBUF_EXPORT ::PROTOBUF_NAMESPACE_ID::FieldMask* Arena::CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::FieldMask>(Arena*);
PROTOBUF_NAMESPACE_CLOSE
PROTOBUF_NAMESPACE_OPEN
class FieldMaskDefaultTypeInternal;
LIBPROTOBUF_EXPORT extern FieldMaskDefaultTypeInternal _FieldMask_default_instance_;
} // namespace protobuf
} // namespace google
namespace google {
namespace protobuf {
// ===================================================================
class PROTOBUF_EXPORT FieldMask final :
public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FieldMask) */ {
class LIBPROTOBUF_EXPORT FieldMask : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FieldMask) */ {
public:
inline FieldMask() : FieldMask(nullptr) {}
~FieldMask() override;
explicit constexpr FieldMask(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized);
FieldMask();
virtual ~FieldMask();
FieldMask(const FieldMask& from);
FieldMask(FieldMask&& from) noexcept
: FieldMask() {
*this = ::std::move(from);
}
inline FieldMask& operator=(const FieldMask& from) {
CopyFrom(from);
return *this;
}
#if LANG_CXX11
FieldMask(FieldMask&& from) noexcept
: FieldMask() {
*this = ::std::move(from);
}
inline FieldMask& operator=(FieldMask&& from) noexcept {
if (this == &from) return *this;
if (GetOwningArena() == from.GetOwningArena()
#ifdef PROTOBUF_FORCE_COPY_IN_MOVE
&& GetOwningArena() != nullptr
#endif // !PROTOBUF_FORCE_COPY_IN_MOVE
) {
InternalSwap(&from);
if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
if (this != &from) InternalSwap(&from);
} else {
CopyFrom(from);
}
return *this;
}
#endif
static const ::google::protobuf::Descriptor* descriptor();
static const FieldMask& default_instance();
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() {
return default_instance().GetMetadata().descriptor;
}
static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() {
return default_instance().GetMetadata().reflection;
}
static const FieldMask& default_instance() {
return *internal_default_instance();
}
static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY
static inline const FieldMask* internal_default_instance() {
return reinterpret_cast<const FieldMask*>(
&_FieldMask_default_instance_);
}
static constexpr int kIndexInFileMessages =
static PROTOBUF_CONSTEXPR int const kIndexInFileMessages =
0;
void Swap(FieldMask* other);
friend void swap(FieldMask& a, FieldMask& b) {
a.Swap(&b);
}
inline void Swap(FieldMask* other) {
if (other == this) return;
#ifdef PROTOBUF_FORCE_COPY_IN_SWAP
if (GetOwningArena() != nullptr &&
GetOwningArena() == other->GetOwningArena()) {
#else // PROTOBUF_FORCE_COPY_IN_SWAP
if (GetOwningArena() == other->GetOwningArena()) {
#endif // !PROTOBUF_FORCE_COPY_IN_SWAP
InternalSwap(other);
} else {
::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);
}
}
void UnsafeArenaSwap(FieldMask* other) {
if (other == this) return;
GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena());
InternalSwap(other);
}
// implements Message ----------------------------------------------
FieldMask* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final {
return CreateMaybeMessage<FieldMask>(arena);
}
using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom;
inline FieldMask* New() const PROTOBUF_FINAL { return New(NULL); }
FieldMask* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
void CopyFrom(const FieldMask& from);
using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom;
void MergeFrom(const FieldMask& from);
private:
static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from);
public:
PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final;
size_t ByteSizeLong() const final;
const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final;
uint8_t* _InternalSerialize(
uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
int GetCachedSize() const final { return _cached_size_.Get(); }
void Clear() PROTOBUF_FINAL;
bool IsInitialized() const PROTOBUF_FINAL;
size_t ByteSizeLong() const PROTOBUF_FINAL;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
private:
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const final;
void SetCachedSize(int size) const PROTOBUF_FINAL;
void InternalSwap(FieldMask* other);
private:
friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata;
static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() {
return "google.protobuf.FieldMask";
inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
return NULL;
}
inline void* MaybeArenaPtr() const {
return NULL;
}
protected:
explicit FieldMask(::PROTOBUF_NAMESPACE_ID::Arena* arena,
bool is_message_owned = false);
private:
static void ArenaDtor(void* object);
inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena);
public:
static const ClassData _class_data_;
const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final;
::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final;
::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
// nested types ----------------------------------------------------
// accessors -------------------------------------------------------
enum : int {
kPathsFieldNumber = 1,
};
// repeated string paths = 1;
int paths_size() const;
private:
int _internal_paths_size() const;
public:
void clear_paths();
const std::string& paths(int index) const;
std::string* mutable_paths(int index);
void set_paths(int index, const std::string& value);
void set_paths(int index, std::string&& value);
static const int kPathsFieldNumber = 1;
const ::std::string& paths(int index) const;
::std::string* mutable_paths(int index);
void set_paths(int index, const ::std::string& value);
#if LANG_CXX11
void set_paths(int index, ::std::string&& value);
#endif
void set_paths(int index, const char* value);
void set_paths(int index, const char* value, size_t size);
std::string* add_paths();
void add_paths(const std::string& value);
void add_paths(std::string&& value);
::std::string* add_paths();
void add_paths(const ::std::string& value);
#if LANG_CXX11
void add_paths(::std::string&& value);
#endif
void add_paths(const char* value);
void add_paths(const char* value, size_t size);
const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>& paths() const;
::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>* mutable_paths();
private:
const std::string& _internal_paths(int index) const;
std::string* _internal_add_paths();
public:
const ::google::protobuf::RepeatedPtrField< ::std::string>& paths() const;
::google::protobuf::RepeatedPtrField< ::std::string>* mutable_paths();
// @@protoc_insertion_point(class_scope:google.protobuf.FieldMask)
private:
class _Internal;
template <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
typedef void InternalArenaConstructable_;
typedef void DestructorSkippable_;
::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string> paths_;
mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
friend struct ::TableStruct_google_2fprotobuf_2ffield_5fmask_2eproto;
::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
::google::protobuf::RepeatedPtrField< ::std::string> paths_;
mutable int _cached_size_;
friend struct ::protobuf_google_2fprotobuf_2ffield_5fmask_2eproto::TableStruct;
friend void ::protobuf_google_2fprotobuf_2ffield_5fmask_2eproto::InitDefaultsFieldMaskImpl();
};
// ===================================================================
@@ -236,41 +185,32 @@ class PROTOBUF_EXPORT FieldMask final :
// FieldMask
// repeated string paths = 1;
inline int FieldMask::_internal_paths_size() const {
return paths_.size();
}
inline int FieldMask::paths_size() const {
return _internal_paths_size();
return paths_.size();
}
inline void FieldMask::clear_paths() {
paths_.Clear();
}
inline std::string* FieldMask::add_paths() {
std::string* _s = _internal_add_paths();
// @@protoc_insertion_point(field_add_mutable:google.protobuf.FieldMask.paths)
return _s;
}
inline const std::string& FieldMask::_internal_paths(int index) const {
inline const ::std::string& FieldMask::paths(int index) const {
// @@protoc_insertion_point(field_get:google.protobuf.FieldMask.paths)
return paths_.Get(index);
}
inline const std::string& FieldMask::paths(int index) const {
// @@protoc_insertion_point(field_get:google.protobuf.FieldMask.paths)
return _internal_paths(index);
}
inline std::string* FieldMask::mutable_paths(int index) {
inline ::std::string* FieldMask::mutable_paths(int index) {
// @@protoc_insertion_point(field_mutable:google.protobuf.FieldMask.paths)
return paths_.Mutable(index);
}
inline void FieldMask::set_paths(int index, const std::string& value) {
inline void FieldMask::set_paths(int index, const ::std::string& value) {
// @@protoc_insertion_point(field_set:google.protobuf.FieldMask.paths)
paths_.Mutable(index)->assign(value);
// @@protoc_insertion_point(field_set:google.protobuf.FieldMask.paths)
}
inline void FieldMask::set_paths(int index, std::string&& value) {
#if LANG_CXX11
inline void FieldMask::set_paths(int index, ::std::string&& value) {
// @@protoc_insertion_point(field_set:google.protobuf.FieldMask.paths)
paths_.Mutable(index)->assign(std::move(value));
// @@protoc_insertion_point(field_set:google.protobuf.FieldMask.paths)
}
#endif
inline void FieldMask::set_paths(int index, const char* value) {
GOOGLE_DCHECK(value != nullptr);
GOOGLE_DCHECK(value != NULL);
paths_.Mutable(index)->assign(value);
// @@protoc_insertion_point(field_set_char:google.protobuf.FieldMask.paths)
}
@@ -279,19 +219,22 @@ inline void FieldMask::set_paths(int index, const char* value, size_t size) {
reinterpret_cast<const char*>(value), size);
// @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldMask.paths)
}
inline std::string* FieldMask::_internal_add_paths() {
inline ::std::string* FieldMask::add_paths() {
// @@protoc_insertion_point(field_add_mutable:google.protobuf.FieldMask.paths)
return paths_.Add();
}
inline void FieldMask::add_paths(const std::string& value) {
inline void FieldMask::add_paths(const ::std::string& value) {
paths_.Add()->assign(value);
// @@protoc_insertion_point(field_add:google.protobuf.FieldMask.paths)
}
inline void FieldMask::add_paths(std::string&& value) {
#if LANG_CXX11
inline void FieldMask::add_paths(::std::string&& value) {
paths_.Add(std::move(value));
// @@protoc_insertion_point(field_add:google.protobuf.FieldMask.paths)
}
#endif
inline void FieldMask::add_paths(const char* value) {
GOOGLE_DCHECK(value != nullptr);
GOOGLE_DCHECK(value != NULL);
paths_.Add()->assign(value);
// @@protoc_insertion_point(field_add_char:google.protobuf.FieldMask.paths)
}
@@ -299,12 +242,12 @@ inline void FieldMask::add_paths(const char* value, size_t size) {
paths_.Add()->assign(reinterpret_cast<const char*>(value), size);
// @@protoc_insertion_point(field_add_pointer:google.protobuf.FieldMask.paths)
}
inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>&
inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
FieldMask::paths() const {
// @@protoc_insertion_point(field_list:google.protobuf.FieldMask.paths)
return paths_;
}
inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string>*
inline ::google::protobuf::RepeatedPtrField< ::std::string>*
FieldMask::mutable_paths() {
// @@protoc_insertion_point(field_mutable_list:google.protobuf.FieldMask.paths)
return &paths_;
@@ -316,9 +259,9 @@ FieldMask::mutable_paths() {
// @@protoc_insertion_point(namespace_scope)
PROTOBUF_NAMESPACE_CLOSE
} // namespace protobuf
} // namespace google
// @@protoc_insertion_point(global_scope)
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_google_2fprotobuf_2ffield_5fmask_2eproto
#endif // PROTOBUF_google_2fprotobuf_2ffield_5fmask_2eproto__INCLUDED
@@ -41,23 +41,14 @@
#include <string>
#include <google/protobuf/stubs/template_util.h>
#include <google/protobuf/generated_enum_util.h>
#include <google/protobuf/port.h>
#include <google/protobuf/stubs/strutil.h>
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
#include <google/protobuf/port_def.inc>
namespace google {
namespace protobuf {
class EnumDescriptor;
class EnumDescriptor;
} // namespace protobuf
} // namespace google
namespace google {
namespace protobuf {
// Returns the EnumDescriptor for enum type E, which must be a
@@ -68,14 +59,16 @@ const EnumDescriptor* GetEnumDescriptor();
namespace internal {
// Helper for EnumType_Parse functions: try to parse the string 'name' as
// an enum name of the given type, returning true and filling in value on
// success, or returning false and leaving value unchanged on failure.
PROTOBUF_EXPORT bool ParseNamedEnum(const EnumDescriptor* descriptor,
ConstStringParam name, int* value);
// Helper for EnumType_Parse functions: try to parse the string 'name' as an
// enum name of the given type, returning true and filling in value on success,
// or returning false and leaving value unchanged on failure.
LIBPROTOBUF_EXPORT bool ParseNamedEnum(const EnumDescriptor* descriptor,
const string& name,
int* value);
template <typename EnumType>
bool ParseNamedEnum(const EnumDescriptor* descriptor, ConstStringParam name,
template<typename EnumType>
bool ParseNamedEnum(const EnumDescriptor* descriptor,
const string& name,
EnumType* value) {
int tmp;
if (!ParseNamedEnum(descriptor, name, &tmp)) return false;
@@ -86,13 +79,10 @@ bool ParseNamedEnum(const EnumDescriptor* descriptor, ConstStringParam name,
// Just a wrapper around printing the name of a value. The main point of this
// function is not to be inlined, so that you can do this without including
// descriptor.h.
PROTOBUF_EXPORT const std::string& NameOfEnum(const EnumDescriptor* descriptor,
int value);
LIBPROTOBUF_EXPORT const string& NameOfEnum(const EnumDescriptor* descriptor, int value);
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
+3 -40
View File
@@ -31,53 +31,16 @@
#ifndef GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
#define GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
#include <type_traits>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/port_def.inc>
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
#include <google/protobuf/stubs/template_util.h>
namespace google {
namespace protobuf {
// This type trait can be used to cause templates to only match proto2 enum
// types.
template <typename T>
struct is_proto_enum : ::std::false_type {};
template <typename T> struct is_proto_enum : ::google::protobuf::internal::false_type {};
namespace internal {
// The table entry format for storing enum name-to-value mapping used with lite
// protos. This struct and the following related functions should only be used
// by protobuf generated code.
struct EnumEntry {
StringPiece name;
int value;
};
// Looks up a numeric enum value given the string name.
PROTOBUF_EXPORT bool LookUpEnumValue(const EnumEntry* enums, size_t size,
StringPiece name, int* value);
// Looks up an enum name given the numeric value.
PROTOBUF_EXPORT int LookUpEnumName(const EnumEntry* enums,
const int* sorted_indices, size_t size,
int value);
// Initializes the list of enum names in std::string form.
PROTOBUF_EXPORT bool InitializeEnumStrings(
const EnumEntry* enums, const int* sorted_indices, size_t size,
internal::ExplicitlyConstructed<std::string>* enum_strings);
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
@@ -1,87 +0,0 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This file contains helpers for generated code.
//
// Nothing in this file should be directly referenced by users of protobufs.
#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_BASES_H__
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_BASES_H__
#include <google/protobuf/parse_context.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/message.h>
// Must come last:
#include <google/protobuf/port_def.inc>
namespace google {
namespace protobuf {
namespace internal {
// To save code size, protos without any fields are derived from ZeroFieldsBase
// rather than Message.
class PROTOBUF_EXPORT ZeroFieldsBase : public Message {
public:
PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
bool IsInitialized() const final { return true; }
size_t ByteSizeLong() const final;
int GetCachedSize() const final { return _cached_size_.Get(); }
const char* _InternalParse(const char* ptr,
internal::ParseContext* ctx) final;
::uint8_t* _InternalSerialize(::uint8_t* target,
io::EpsCopyOutputStream* stream) const final;
protected:
constexpr ZeroFieldsBase() {}
explicit ZeroFieldsBase(Arena* arena, bool is_message_owned)
: Message(arena, is_message_owned) {}
ZeroFieldsBase(const ZeroFieldsBase&) = delete;
ZeroFieldsBase& operator=(const ZeroFieldsBase&) = delete;
~ZeroFieldsBase() override;
void SetCachedSize(int size) const final { _cached_size_.Set(size); }
static void MergeImpl(Message* to, const Message& from);
static void CopyImpl(Message* to, const Message& from);
void InternalSwap(ZeroFieldsBase* other);
mutable internal::CachedSize _cached_size_;
};
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_BASES_H__
File diff suppressed because it is too large Load Diff
@@ -42,36 +42,45 @@
#include <vector>
#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/descriptor.h>
// TODO(jasonh): Remove this once the compiler change to directly include this
// is released to components.
#include <google/protobuf/generated_enum_reflection.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/port.h>
#include <google/protobuf/message.h>
#include <google/protobuf/metadata.h>
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/port_def.inc>
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
namespace google {
namespace upb {
namespace google_opensource {
class GMR_Handlers;
} // namespace google_opensource
} // namespace upb
namespace protobuf {
class DescriptorPool;
class MapKey;
class MapValueRef;
class MessageLayoutInspector;
class Message;
struct Metadata;
} // namespace protobuf
} // namespace google
namespace google {
namespace protobuf {
namespace flat {
class MetadataBuilder;
} // namespace flat
} // namespace protobuf
namespace protobuf {
namespace internal {
class DefaultEmptyOneof;
// Defined in this file.
class GeneratedMessageReflection;
// Defined in other files.
class ExtensionSet; // extension_set.h
class WeakFieldMap; // weak_field_map.h
class ExtensionSet; // extension_set.h
class WeakFieldMap; // weak_field_map.h
// This struct describes the internal layout of the message, hence this is
// used to act on the message reflectively.
@@ -79,17 +88,17 @@ class WeakFieldMap; // weak_field_map.h
// used to obtain pointers to default instances of embedded
// messages, which GetMessage() will return if the particular
// sub-message has not been initialized yet. (Thus, all
// embedded message fields *must* have non-null pointers
// embedded message fields *must* have non-NULL pointers
// in the default instance.)
// offsets: An array of ints giving the byte offsets.
// For each oneof or weak field, the offset is relative to the
// default_instance. These can be computed at compile time
// using the
// PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET()
// GOOGLE_PROTOBUF_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET()
// macro. For each none oneof field, the offset is related to
// the start of the message object. These can be computed at
// compile time using the
// PROTO2_GENERATED_MESSAGE_FIELD_OFFSET() macro.
// GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET() macro.
// Besides offsets for all fields, this array also contains
// offsets for oneof unions. The offset of the i-th oneof union
// is offsets[descriptor->field_count() + i].
@@ -107,7 +116,7 @@ class WeakFieldMap; // weak_field_map.h
// message, or -1 if the message type has no extension
// ranges.
// oneof_case_offset: Offset in the message of an array of uint32s of
// size descriptor->oneof_decl_count(). Each uint32_t
// size descriptor->oneof_decl_count(). Each uint32
// indicates what field is set for each oneof.
// object_size: The size of a message object of this type, as measured
// by sizeof().
@@ -119,88 +128,62 @@ class WeakFieldMap; // weak_field_map.h
struct ReflectionSchema {
public:
// Size of a google::protobuf::Message object of this type.
uint32_t GetObjectSize() const { return static_cast<uint32_t>(object_size_); }
bool InRealOneof(const FieldDescriptor* field) const {
return field->containing_oneof() &&
!field->containing_oneof()->is_synthetic();
}
uint32 GetObjectSize() const { return static_cast<uint32>(object_size_); }
// Offset of a non-oneof field. Getting a field offset is slightly more
// efficient when we know statically that it is not a oneof field.
uint32_t GetFieldOffsetNonOneof(const FieldDescriptor* field) const {
GOOGLE_DCHECK(!InRealOneof(field));
return OffsetValue(offsets_[field->index()], field->type());
uint32 GetFieldOffsetNonOneof(const FieldDescriptor* field) const {
GOOGLE_DCHECK(!field->containing_oneof());
return offsets_[field->index()];
}
// Offset of any field.
uint32_t GetFieldOffset(const FieldDescriptor* field) const {
if (InRealOneof(field)) {
uint32 GetFieldOffset(const FieldDescriptor* field) const {
if (field->containing_oneof()) {
size_t offset =
static_cast<size_t>(field->containing_type()->field_count() +
field->containing_oneof()->index());
return OffsetValue(offsets_[offset], field->type());
field->containing_oneof()->index());
return offsets_[offset];
} else {
return GetFieldOffsetNonOneof(field);
}
}
bool IsFieldInlined(const FieldDescriptor* field) const {
return Inlined(offsets_[field->index()], field->type());
}
uint32_t GetOneofCaseOffset(const OneofDescriptor* oneof_descriptor) const {
return static_cast<uint32_t>(oneof_case_offset_) +
static_cast<uint32_t>(
static_cast<size_t>(oneof_descriptor->index()) *
sizeof(uint32_t));
uint32 GetOneofCaseOffset(const OneofDescriptor* oneof_descriptor) const {
return static_cast<uint32>(oneof_case_offset_) +
static_cast<uint32>(
static_cast<size_t>(oneof_descriptor->index()) * sizeof(uint32));
}
bool HasHasbits() const { return has_bits_offset_ != -1; }
// Bit index within the bit array of hasbits. Bit order is low-to-high.
uint32_t HasBitIndex(const FieldDescriptor* field) const {
if (has_bits_offset_ == -1) return static_cast<uint32_t>(-1);
uint32 HasBitIndex(const FieldDescriptor* field) const {
GOOGLE_DCHECK(HasHasbits());
return has_bit_indices_[field->index()];
}
// Byte offset of the hasbits array.
uint32_t HasBitsOffset() const {
uint32 HasBitsOffset() const {
GOOGLE_DCHECK(HasHasbits());
return static_cast<uint32_t>(has_bits_offset_);
}
bool HasInlinedString() const { return inlined_string_donated_offset_ != -1; }
// Bit index within the bit array of _inlined_string_donated_. Bit order is
// low-to-high.
uint32_t InlinedStringIndex(const FieldDescriptor* field) const {
GOOGLE_DCHECK(HasInlinedString());
return inlined_string_indices_[field->index()];
}
// Byte offset of the _inlined_string_donated_ array.
uint32_t InlinedStringDonatedOffset() const {
GOOGLE_DCHECK(HasInlinedString());
return static_cast<uint32_t>(inlined_string_donated_offset_);
return static_cast<uint32>(has_bits_offset_);
}
// The offset of the InternalMetadataWithArena member.
// For Lite this will actually be an InternalMetadataWithArenaLite.
// The schema doesn't contain enough information to distinguish between
// these two cases.
uint32_t GetMetadataOffset() const {
return static_cast<uint32_t>(metadata_offset_);
uint32 GetMetadataOffset() const {
return static_cast<uint32>(metadata_offset_);
}
// Whether this message has an ExtensionSet.
bool HasExtensionSet() const { return extensions_offset_ != -1; }
// The offset of the ExtensionSet in this message.
uint32_t GetExtensionSetOffset() const {
uint32 GetExtensionSetOffset() const {
GOOGLE_DCHECK(HasExtensionSet());
return static_cast<uint32_t>(extensions_offset_);
return static_cast<uint32>(extensions_offset_);
}
// The off set of WeakFieldMap when the message contains weak fields.
@@ -213,33 +196,9 @@ struct ReflectionSchema {
// Returns a pointer to the default value for this field. The size and type
// of the underlying data depends on the field's type.
const void* GetFieldDefault(const FieldDescriptor* field) const {
return reinterpret_cast<const uint8_t*>(default_instance_) +
OffsetValue(offsets_[field->index()], field->type());
}
// Returns true if the field is implicitly backed by LazyField.
bool IsEagerlyVerifiedLazyField(const FieldDescriptor* field) const {
GOOGLE_DCHECK_EQ(field->type(), FieldDescriptor::TYPE_MESSAGE);
(void)field;
return false;
}
// Returns true if the field's accessor is called by any external code (aka,
// non proto library code).
bool IsFieldUsed(const FieldDescriptor* field) const {
(void)field;
return true;
}
bool IsFieldStripped(const FieldDescriptor* field) const {
(void)field;
return false;
}
bool IsMessageStripped(const Descriptor* descriptor) const {
(void)descriptor;
return false;
const void *GetFieldDefault(const FieldDescriptor* field) const {
return reinterpret_cast<const uint8*>(default_instance_) +
offsets_[field->index()];
}
@@ -250,39 +209,16 @@ struct ReflectionSchema {
// them, ie.
//
// ReflectionSchema schema = {a, b, c, d, e, ...};
// private:
// private:
const Message* default_instance_;
const uint32_t* offsets_;
const uint32_t* has_bit_indices_;
const uint32* offsets_;
const uint32* has_bit_indices_;
int has_bits_offset_;
int metadata_offset_;
int extensions_offset_;
int oneof_case_offset_;
int object_size_;
int weak_field_map_offset_;
const uint32_t* inlined_string_indices_;
int inlined_string_donated_offset_;
// We tag offset values to provide additional data about fields (such as
// "unused" or "lazy" or "inlined").
static uint32_t OffsetValue(uint32_t v, FieldDescriptor::Type type) {
if (type == FieldDescriptor::TYPE_MESSAGE ||
type == FieldDescriptor::TYPE_STRING ||
type == FieldDescriptor::TYPE_BYTES) {
return v & 0x7FFFFFFEu;
}
return v & 0x7FFFFFFFu;
}
static bool Inlined(uint32_t v, FieldDescriptor::Type type) {
if (type == FieldDescriptor::TYPE_STRING ||
type == FieldDescriptor::TYPE_BYTES) {
return (v & 1u) != 0u;
} else {
// Non string/byte fields are not inlined.
return false;
}
}
};
// Structs that the code generator emits directly to describe a message.
@@ -292,71 +228,501 @@ struct ReflectionSchema {
// EXPERIMENTAL: these are changing rapidly, and may completely disappear
// or merge with ReflectionSchema.
struct MigrationSchema {
int32_t offsets_index;
int32_t has_bit_indices_index;
int32_t inlined_string_indices_index;
int32 offsets_index;
int32 has_bit_indices_index;
int object_size;
};
// This struct tries to reduce unnecessary padding.
// The num_xxx might not be close to their respective pointer, but this saves
// padding.
struct PROTOBUF_EXPORT DescriptorTable {
mutable bool is_initialized;
bool is_eager;
int size; // of serialized descriptor
const char* descriptor;
const char* filename;
once_flag* once;
const DescriptorTable* const* deps;
int num_deps;
int num_messages;
const MigrationSchema* schemas;
const Message* const* default_instances;
const uint32_t* offsets;
// update the following descriptor arrays.
Metadata* file_level_metadata;
const EnumDescriptor** file_level_enum_descriptors;
const ServiceDescriptor** file_level_service_descriptors;
// THIS CLASS IS NOT INTENDED FOR DIRECT USE. It is intended for use
// by generated code. This class is just a big hack that reduces code
// size.
//
// A GeneratedMessageReflection is an implementation of Reflection
// which expects all fields to be backed by simple variables located in
// memory. The locations are given using a base pointer and a set of
// offsets.
//
// It is required that the user represents fields of each type in a standard
// way, so that GeneratedMessageReflection can cast the void* pointer to
// the appropriate type. For primitive fields and string fields, each field
// should be represented using the obvious C++ primitive type. Enums and
// Messages are different:
// - Singular Message fields are stored as a pointer to a Message. These
// should start out NULL, except for in the default instance where they
// should start out pointing to other default instances.
// - Enum fields are stored as an int. This int must always contain
// a valid value, such that EnumDescriptor::FindValueByNumber() would
// not return NULL.
// - Repeated fields are stored as RepeatedFields or RepeatedPtrFields
// of whatever type the individual field would be. Strings and
// Messages use RepeatedPtrFields while everything else uses
// RepeatedFields.
class LIBPROTOBUF_EXPORT GeneratedMessageReflection PROTOBUF_FINAL : public Reflection {
public:
// Constructs a GeneratedMessageReflection.
// Parameters:
// descriptor: The descriptor for the message type being implemented.
// schema: The description of the internal guts of the message.
// pool: DescriptorPool to search for extension definitions. Only
// used by FindKnownExtensionByName() and
// FindKnownExtensionByNumber().
// factory: MessageFactory to use to construct extension messages.
GeneratedMessageReflection(const Descriptor* descriptor,
const ReflectionSchema& schema,
const DescriptorPool* pool,
MessageFactory* factory);
~GeneratedMessageReflection();
// implements Reflection -------------------------------------------
const UnknownFieldSet& GetUnknownFields(const Message& message) const;
UnknownFieldSet* MutableUnknownFields(Message* message) const;
size_t SpaceUsedLong(const Message& message) const;
bool HasField(const Message& message, const FieldDescriptor* field) const;
int FieldSize(const Message& message, const FieldDescriptor* field) const;
void ClearField(Message* message, const FieldDescriptor* field) const;
bool HasOneof(const Message& message,
const OneofDescriptor* oneof_descriptor) const;
void ClearOneof(Message* message, const OneofDescriptor* field) const;
void RemoveLast(Message* message, const FieldDescriptor* field) const;
Message* ReleaseLast(Message* message, const FieldDescriptor* field) const;
void Swap(Message* message1, Message* message2) const;
void SwapFields(Message* message1, Message* message2,
const std::vector<const FieldDescriptor*>& fields) const;
void SwapElements(Message* message, const FieldDescriptor* field,
int index1, int index2) const;
void ListFields(const Message& message,
std::vector<const FieldDescriptor*>* output) const;
int32 GetInt32 (const Message& message,
const FieldDescriptor* field) const;
int64 GetInt64 (const Message& message,
const FieldDescriptor* field) const;
uint32 GetUInt32(const Message& message,
const FieldDescriptor* field) const;
uint64 GetUInt64(const Message& message,
const FieldDescriptor* field) const;
float GetFloat (const Message& message,
const FieldDescriptor* field) const;
double GetDouble(const Message& message,
const FieldDescriptor* field) const;
bool GetBool (const Message& message,
const FieldDescriptor* field) const;
string GetString(const Message& message,
const FieldDescriptor* field) const;
const string& GetStringReference(const Message& message,
const FieldDescriptor* field,
string* scratch) const;
const EnumValueDescriptor* GetEnum(const Message& message,
const FieldDescriptor* field) const;
int GetEnumValue(const Message& message,
const FieldDescriptor* field) const;
const Message& GetMessage(const Message& message,
const FieldDescriptor* field,
MessageFactory* factory = NULL) const;
const FieldDescriptor* GetOneofFieldDescriptor(
const Message& message,
const OneofDescriptor* oneof_descriptor) const;
private:
bool ContainsMapKey(const Message& message,
const FieldDescriptor* field,
const MapKey& key) const;
bool InsertOrLookupMapValue(Message* message,
const FieldDescriptor* field,
const MapKey& key,
MapValueRef* val) const;
bool DeleteMapValue(Message* message,
const FieldDescriptor* field,
const MapKey& key) const;
MapIterator MapBegin(
Message* message,
const FieldDescriptor* field) const;
MapIterator MapEnd(
Message* message,
const FieldDescriptor* field) const;
int MapSize(const Message& message, const FieldDescriptor* field) const;
public:
void SetInt32 (Message* message,
const FieldDescriptor* field, int32 value) const;
void SetInt64 (Message* message,
const FieldDescriptor* field, int64 value) const;
void SetUInt32(Message* message,
const FieldDescriptor* field, uint32 value) const;
void SetUInt64(Message* message,
const FieldDescriptor* field, uint64 value) const;
void SetFloat (Message* message,
const FieldDescriptor* field, float value) const;
void SetDouble(Message* message,
const FieldDescriptor* field, double value) const;
void SetBool (Message* message,
const FieldDescriptor* field, bool value) const;
void SetString(Message* message,
const FieldDescriptor* field,
const string& value) const;
void SetEnum (Message* message, const FieldDescriptor* field,
const EnumValueDescriptor* value) const;
void SetEnumValue(Message* message, const FieldDescriptor* field,
int value) const;
Message* MutableMessage(Message* message, const FieldDescriptor* field,
MessageFactory* factory = NULL) const;
void SetAllocatedMessage(Message* message,
Message* sub_message,
const FieldDescriptor* field) const;
Message* ReleaseMessage(Message* message, const FieldDescriptor* field,
MessageFactory* factory = NULL) const;
int32 GetRepeatedInt32 (const Message& message,
const FieldDescriptor* field, int index) const;
int64 GetRepeatedInt64 (const Message& message,
const FieldDescriptor* field, int index) const;
uint32 GetRepeatedUInt32(const Message& message,
const FieldDescriptor* field, int index) const;
uint64 GetRepeatedUInt64(const Message& message,
const FieldDescriptor* field, int index) const;
float GetRepeatedFloat (const Message& message,
const FieldDescriptor* field, int index) const;
double GetRepeatedDouble(const Message& message,
const FieldDescriptor* field, int index) const;
bool GetRepeatedBool (const Message& message,
const FieldDescriptor* field, int index) const;
string GetRepeatedString(const Message& message,
const FieldDescriptor* field, int index) const;
const string& GetRepeatedStringReference(const Message& message,
const FieldDescriptor* field,
int index, string* scratch) const;
const EnumValueDescriptor* GetRepeatedEnum(const Message& message,
const FieldDescriptor* field,
int index) const;
int GetRepeatedEnumValue(const Message& message,
const FieldDescriptor* field,
int index) const;
const Message& GetRepeatedMessage(const Message& message,
const FieldDescriptor* field,
int index) const;
// Set the value of a field.
void SetRepeatedInt32 (Message* message,
const FieldDescriptor* field, int index, int32 value) const;
void SetRepeatedInt64 (Message* message,
const FieldDescriptor* field, int index, int64 value) const;
void SetRepeatedUInt32(Message* message,
const FieldDescriptor* field, int index, uint32 value) const;
void SetRepeatedUInt64(Message* message,
const FieldDescriptor* field, int index, uint64 value) const;
void SetRepeatedFloat (Message* message,
const FieldDescriptor* field, int index, float value) const;
void SetRepeatedDouble(Message* message,
const FieldDescriptor* field, int index, double value) const;
void SetRepeatedBool (Message* message,
const FieldDescriptor* field, int index, bool value) const;
void SetRepeatedString(Message* message,
const FieldDescriptor* field, int index,
const string& value) const;
void SetRepeatedEnum(Message* message, const FieldDescriptor* field,
int index, const EnumValueDescriptor* value) const;
void SetRepeatedEnumValue(Message* message, const FieldDescriptor* field,
int index, int value) const;
// Get a mutable pointer to a field with a message type.
Message* MutableRepeatedMessage(Message* message,
const FieldDescriptor* field,
int index) const;
void AddInt32 (Message* message,
const FieldDescriptor* field, int32 value) const;
void AddInt64 (Message* message,
const FieldDescriptor* field, int64 value) const;
void AddUInt32(Message* message,
const FieldDescriptor* field, uint32 value) const;
void AddUInt64(Message* message,
const FieldDescriptor* field, uint64 value) const;
void AddFloat (Message* message,
const FieldDescriptor* field, float value) const;
void AddDouble(Message* message,
const FieldDescriptor* field, double value) const;
void AddBool (Message* message,
const FieldDescriptor* field, bool value) const;
void AddString(Message* message,
const FieldDescriptor* field, const string& value) const;
void AddEnum(Message* message,
const FieldDescriptor* field,
const EnumValueDescriptor* value) const;
void AddEnumValue(Message* message,
const FieldDescriptor* field,
int value) const;
Message* AddMessage(Message* message, const FieldDescriptor* field,
MessageFactory* factory = NULL) const;
void AddAllocatedMessage(
Message* message, const FieldDescriptor* field,
Message* new_entry) const;
const FieldDescriptor* FindKnownExtensionByName(const string& name) const;
const FieldDescriptor* FindKnownExtensionByNumber(int number) const;
bool SupportsUnknownEnumValues() const;
// This value for arena_offset_ indicates that there is no arena pointer in
// this message (e.g., old generated code).
static const int kNoArenaPointer = -1;
// This value for unknown_field_offset_ indicates that there is no
// UnknownFieldSet in this message, and that instead, we are using the
// Zero-Overhead Arena Pointer trick. When this is the case, arena_offset_
// actually indexes to an InternalMetadataWithArena instance, which can return
// either an arena pointer or an UnknownFieldSet or both. It is never the case
// that unknown_field_offset_ == kUnknownFieldSetInMetadata && arena_offset_
// == kNoArenaPointer.
static const int kUnknownFieldSetInMetadata = -1;
protected:
void* MutableRawRepeatedField(
Message* message, const FieldDescriptor* field, FieldDescriptor::CppType,
int ctype, const Descriptor* desc) const;
const void* GetRawRepeatedField(
const Message& message, const FieldDescriptor* field,
FieldDescriptor::CppType, int ctype,
const Descriptor* desc) const;
virtual MessageFactory* GetMessageFactory() const;
virtual void* RepeatedFieldData(
Message* message, const FieldDescriptor* field,
FieldDescriptor::CppType cpp_type,
const Descriptor* message_type) const;
private:
friend class google::protobuf::flat::MetadataBuilder;
friend class upb::google_opensource::GMR_Handlers;
const Descriptor* const descriptor_;
const ReflectionSchema schema_;
const DescriptorPool* const descriptor_pool_;
MessageFactory* const message_factory_;
// Last non weak field index. This is an optimization when most weak fields
// are at the end of the containing message. If a message proto doesn't
// contain weak fields, then this field equals descriptor_->field_count().
int last_non_weak_field_index_;
template <class T>
const T& GetRawNonOneof(const Message& message,
const FieldDescriptor* field) const;
template <class T>
T* MutableRawNonOneof(Message* message, const FieldDescriptor* field) const;
template <typename Type>
const Type& GetRaw(const Message& message,
const FieldDescriptor* field) const;
template <typename Type>
inline Type* MutableRaw(Message* message,
const FieldDescriptor* field) const;
template <typename Type>
inline const Type& DefaultRaw(const FieldDescriptor* field) const;
inline const uint32* GetHasBits(const Message& message) const;
inline uint32* MutableHasBits(Message* message) const;
inline uint32 GetOneofCase(
const Message& message,
const OneofDescriptor* oneof_descriptor) const;
inline uint32* MutableOneofCase(
Message* message,
const OneofDescriptor* oneof_descriptor) const;
inline const ExtensionSet& GetExtensionSet(const Message& message) const;
inline ExtensionSet* MutableExtensionSet(Message* message) const;
inline Arena* GetArena(Message* message) const;
inline const InternalMetadataWithArena& GetInternalMetadataWithArena(
const Message& message) const;
inline InternalMetadataWithArena*
MutableInternalMetadataWithArena(Message* message) const;
inline bool HasBit(const Message& message,
const FieldDescriptor* field) const;
inline void SetBit(Message* message,
const FieldDescriptor* field) const;
inline void ClearBit(Message* message,
const FieldDescriptor* field) const;
inline void SwapBit(Message* message1,
Message* message2,
const FieldDescriptor* field) const;
// This function only swaps the field. Should swap corresponding has_bit
// before or after using this function.
void SwapField(Message* message1,
Message* message2,
const FieldDescriptor* field) const;
void SwapOneofField(Message* message1,
Message* message2,
const OneofDescriptor* oneof_descriptor) const;
inline bool HasOneofField(const Message& message,
const FieldDescriptor* field) const;
inline void SetOneofCase(Message* message,
const FieldDescriptor* field) const;
inline void ClearOneofField(Message* message,
const FieldDescriptor* field) const;
template <typename Type>
inline const Type& GetField(const Message& message,
const FieldDescriptor* field) const;
template <typename Type>
inline void SetField(Message* message,
const FieldDescriptor* field, const Type& value) const;
template <typename Type>
inline Type* MutableField(Message* message,
const FieldDescriptor* field) const;
template <typename Type>
inline const Type& GetRepeatedField(const Message& message,
const FieldDescriptor* field,
int index) const;
template <typename Type>
inline const Type& GetRepeatedPtrField(const Message& message,
const FieldDescriptor* field,
int index) const;
template <typename Type>
inline void SetRepeatedField(Message* message,
const FieldDescriptor* field, int index,
Type value) const;
template <typename Type>
inline Type* MutableRepeatedField(Message* message,
const FieldDescriptor* field,
int index) const;
template <typename Type>
inline void AddField(Message* message,
const FieldDescriptor* field, const Type& value) const;
template <typename Type>
inline Type* AddField(Message* message,
const FieldDescriptor* field) const;
int GetExtensionNumberOrDie(const Descriptor* type) const;
// Internal versions of EnumValue API perform no checking. Called after checks
// by public methods.
void SetEnumValueInternal(Message* message,
const FieldDescriptor* field,
int value) const;
void SetRepeatedEnumValueInternal(Message* message,
const FieldDescriptor* field,
int index,
int value) const;
void AddEnumValueInternal(Message* message,
const FieldDescriptor* field,
int value) const;
Message* UnsafeArenaReleaseMessage(Message* message,
const FieldDescriptor* field,
MessageFactory* factory = NULL) const;
void UnsafeArenaSetAllocatedMessage(Message* message,
Message* sub_message,
const FieldDescriptor* field) const;
internal::MapFieldBase* MapData(
Message* message, const FieldDescriptor* field) const;
friend inline // inline so nobody can call this function.
void
RegisterAllTypesInternal(const Metadata* file_level_metadata, int size);
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratedMessageReflection);
};
enum {
// Tag used on offsets for fields that don't have a real offset.
// For example, weak message fields go into the WeakFieldMap and not in an
// actual field.
kInvalidFieldOffsetTag = 0x40000000u,
};
// There are some places in proto2 where dynamic_cast would be useful as an
// optimization. For example, take Message::MergeFrom(const Message& other).
// For a given generated message FooMessage, we generate these two methods:
// void MergeFrom(const FooMessage& other);
// void MergeFrom(const Message& other);
// The former method can be implemented directly in terms of FooMessage's
// inline accessors, but the latter method must work with the reflection
// interface. However, if the parameter to the latter method is actually of
// type FooMessage, then we'd like to be able to just call the other method
// as an optimization. So, we use dynamic_cast to check this.
//
// That said, dynamic_cast requires RTTI, which many people like to disable
// for performance and code size reasons. When RTTI is not available, we
// still need to produce correct results. So, in this case we have to fall
// back to using reflection, which is what we would have done anyway if the
// objects were not of the exact same class.
//
// dynamic_cast_if_available() implements this logic. If RTTI is
// enabled, it does a dynamic_cast. If RTTI is disabled, it just returns
// NULL.
//
// If you need to compile without RTTI, simply #define GOOGLE_PROTOBUF_NO_RTTI.
// On MSVC, this should be detected automatically.
template<typename To, typename From>
inline To dynamic_cast_if_available(From from) {
#if defined(GOOGLE_PROTOBUF_NO_RTTI) || (defined(_MSC_VER)&&!defined(_CPPRTTI))
// Avoid the compiler warning about unused variables.
(void)from;
return NULL;
#else
return dynamic_cast<To>(from);
#endif
}
// AssignDescriptors() pulls the compiled FileDescriptor from the DescriptorPool
// and uses it to populate all of the global variables which store pointers to
// the descriptor objects. It also constructs the reflection objects. It is
// called the first time anyone calls descriptor() or GetReflection() on one of
// the types defined in the file. AssignDescriptors() is thread-safe.
void PROTOBUF_EXPORT AssignDescriptors(const DescriptorTable* table,
bool eager = false);
// Tries to downcast this message to a generated message type.
// Returns NULL if this class is not an instance of T.
//
// This is like dynamic_cast_if_available, except it works even when
// dynamic_cast is not available by using Reflection. However it only works
// with Message objects.
//
// TODO(haberman): can we remove dynamic_cast_if_available in favor of this?
template <typename T>
T* DynamicCastToGenerated(const Message* from) {
// Compile-time assert that T is a generated type that has a
// default_instance() accessor, but avoid actually calling it.
const T&(*get_default_instance)() = &T::default_instance;
(void)get_default_instance;
// Overload used to implement GetMetadataStatic in the generated code.
// See comments in compiler/cpp/internal/file.cc as to why.
// It takes a `Metadata` and returns it to allow for tail calls and reduce
// binary size.
Metadata PROTOBUF_EXPORT AssignDescriptors(const DescriptorTable* (*table)(),
internal::once_flag* once,
const Metadata& metadata);
// Compile-time assert that T is a subclass of google::protobuf::Message.
const Message* unused = static_cast<T*>(NULL);
(void)unused;
#if defined(GOOGLE_PROTOBUF_NO_RTTI) || \
(defined(_MSC_VER) && !defined(_CPPRTTI))
bool ok = &T::default_instance() ==
from->GetReflection()->GetMessageFactory()->GetPrototype(
from->GetDescriptor());
return ok ? down_cast<T*>(from) : NULL;
#else
return dynamic_cast<T*>(from);
#endif
}
template <typename T>
T* DynamicCastToGenerated(Message* from) {
const Message* message_const = from;
return const_cast<T*>(DynamicCastToGenerated<const T>(message_const));
}
LIBPROTOBUF_EXPORT void AssignDescriptors(
const string& filename, const MigrationSchema* schemas,
const Message* const* default_instances_, const uint32* offsets,
MessageFactory* factory,
// update the following descriptor arrays.
Metadata* file_level_metadata,
const EnumDescriptor** file_level_enum_descriptors,
const ServiceDescriptor** file_level_service_descriptors);
LIBPROTOBUF_EXPORT void RegisterAllTypes(const Metadata* file_level_metadata, int size);
// These cannot be in lite so we put them in the reflection.
PROTOBUF_EXPORT void UnknownFieldSetSerializer(const uint8_t* base,
uint32_t offset, uint32_t tag,
uint32_t has_offset,
io::CodedOutputStream* output);
struct PROTOBUF_EXPORT AddDescriptorsRunner {
explicit AddDescriptorsRunner(const DescriptorTable* table);
};
LIBPROTOBUF_EXPORT void UnknownFieldSetSerializer(const uint8* base, uint32 offset, uint32 tag,
uint32 has_offset,
::google::protobuf::io::CodedOutputStream* output);
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__
@@ -0,0 +1,103 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/stubs/type_traits.h>
#include <google/protobuf/generated_message_table_driven_lite.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/metadata.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/wire_format_lite_inl.h>
namespace google {
namespace protobuf {
namespace internal {
namespace {
UnknownFieldSet* MutableUnknownFields(MessageLite* msg, int64 arena_offset) {
return Raw<InternalMetadataWithArena>(msg, arena_offset)
->mutable_unknown_fields();
}
struct UnknownFieldHandler {
static bool Skip(MessageLite* msg, const ParseTable& table,
io::CodedInputStream* input,
int tag) {
GOOGLE_DCHECK(table.unknown_field_set);
return WireFormat::SkipField(input, tag,
MutableUnknownFields(msg, table.arena_offset));
}
static void Varint(MessageLite* msg, const ParseTable& table,
int tag, int value) {
GOOGLE_DCHECK(table.unknown_field_set);
MutableUnknownFields(msg, table.arena_offset)->AddVarint(
WireFormatLite::GetTagFieldNumber(tag), value);
}
static bool ParseExtension(
MessageLite* msg, const ParseTable& table,
io::CodedInputStream* input, int tag) {
ExtensionSet* extensions = GetExtensionSet(msg, table.extension_offset);
if (extensions == NULL) {
return false;
}
const Message* prototype = down_cast<const Message*>(
table.default_instance());
GOOGLE_DCHECK(prototype != NULL);
GOOGLE_DCHECK(table.unknown_field_set);
UnknownFieldSet* unknown_fields =
MutableUnknownFields(msg, table.arena_offset);
return extensions->ParseField(tag, input, prototype, unknown_fields);
}
};
} // namespace
bool MergePartialFromCodedStream(
MessageLite* msg, const ParseTable& table, io::CodedInputStream* input) {
return MergePartialFromCodedStreamImpl<UnknownFieldHandler,
InternalMetadataWithArena>(msg, table,
input);
}
} // namespace internal
} // namespace protobuf
} // namespace google
@@ -36,6 +36,10 @@
#include <google/protobuf/map_field_lite.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/wire_format_lite_inl.h>
#if LANG_CXX11
#define PROTOBUF_CONSTEXPR constexpr
// We require C++11 and Clang to use constexpr for variables, as GCC 4.8
// requires constexpr to be consistent between declarations of variables
@@ -47,72 +51,37 @@
#define PROTOBUF_CONSTEXPR_VAR
#endif // !_clang
#ifdef SWIG
#error "You cannot SWIG proto headers"
#else
#define PROTOBUF_CONSTEXPR
#define PROTOBUF_CONSTEXPR_VAR
#endif
#include <google/protobuf/port_def.inc>
namespace google {
namespace protobuf {
namespace internal {
// Processing-type masks.
static constexpr const unsigned char kOneofMask = 0x40;
static constexpr const unsigned char kRepeatedMask = 0x20;
static PROTOBUF_CONSTEXPR const unsigned char kOneofMask = 0x40;
static PROTOBUF_CONSTEXPR const unsigned char kRepeatedMask = 0x20;
// Mask for the raw type: either a WireFormatLite::FieldType or one of the
// ProcessingTypes below, without the oneof or repeated flag.
static constexpr const unsigned char kTypeMask = 0x1f;
static PROTOBUF_CONSTEXPR const unsigned char kTypeMask = 0x1f;
// Wire type masks.
static constexpr const unsigned char kNotPackedMask = 0x10;
static constexpr const unsigned char kInvalidMask = 0x20;
static PROTOBUF_CONSTEXPR const unsigned char kNotPackedMask = 0x10;
static PROTOBUF_CONSTEXPR const unsigned char kInvalidMask = 0x20;
enum ProcessingTypes {
TYPE_STRING_CORD = 19,
TYPE_STRING_STRING_PIECE = 20,
TYPE_BYTES_CORD = 21,
TYPE_BYTES_STRING_PIECE = 22,
TYPE_STRING_INLINED = 23,
TYPE_BYTES_INLINED = 24,
TYPE_MAP = 25,
TYPE_MAP = 23,
};
#if LANG_CXX11
static_assert(TYPE_MAP < kRepeatedMask, "Invalid enum");
struct PROTOBUF_EXPORT FieldMetadata {
uint32_t offset; // offset of this field in the struct
uint32_t tag; // field * 8 + wire_type
// byte offset * 8 + bit_offset;
// if the high bit is set then this is the byte offset of the oneof_case
// for this field.
uint32_t has_offset;
uint32_t type; // the type of this field.
const void* ptr; // auxiliary data
// From the serializer point of view each fundamental type can occur in
// 4 different ways. For simplicity we treat all combinations as a cartesion
// product although not all combinations are allowed.
enum FieldTypeClass {
kPresence,
kNoPresence,
kRepeated,
kPacked,
kOneOf,
kNumTypeClasses // must be last enum
};
// C++ protobuf has 20 fundamental types, were we added Cord and StringPiece
// and also distinguish the same types if they have different wire format.
enum {
kCordType = 19,
kStringPieceType = 20,
kInlinedType = 21,
kNumTypes = 21,
kSpecial = kNumTypes * kNumTypeClasses,
};
static int CalculateType(int fundamental_type, FieldTypeClass type_class);
};
#endif
// TODO(ckennelly): Add a static assertion to ensure that these masks do not
// conflict with wiretypes.
@@ -120,12 +89,12 @@ struct PROTOBUF_EXPORT FieldMetadata {
// ParseTableField is kept small to help simplify instructions for computing
// offsets, as we will always need this information to parse a field.
// Additional data, needed for some types, is stored in
// AuxiliaryParseTableField.
// AuxillaryParseTableField.
struct ParseTableField {
uint32_t offset;
uint32 offset;
// The presence_index ordinarily represents a has_bit index, but for fields
// inside a oneof it represents the index in _oneof_case_.
uint32_t presence_index;
uint32 presence_index;
unsigned char normal_wiretype;
unsigned char packed_wiretype;
@@ -138,7 +107,7 @@ struct ParseTableField {
struct ParseTable;
union AuxiliaryParseTableField {
union AuxillaryParseTableField {
typedef bool (*EnumValidator)(int);
// Enums
@@ -155,6 +124,7 @@ union AuxiliaryParseTableField {
const MessageLite* default_message() const {
return static_cast<const MessageLite*>(default_message_void);
}
const ParseTable* parse_table;
};
message_aux messages;
// Strings
@@ -169,28 +139,33 @@ union AuxiliaryParseTableField {
};
map_aux maps;
AuxiliaryParseTableField() = default;
constexpr AuxiliaryParseTableField(AuxiliaryParseTableField::enum_aux e)
: enums(e) {}
constexpr AuxiliaryParseTableField(AuxiliaryParseTableField::message_aux m)
: messages(m) {}
constexpr AuxiliaryParseTableField(AuxiliaryParseTableField::string_aux s)
: strings(s) {}
constexpr AuxiliaryParseTableField(AuxiliaryParseTableField::map_aux m)
#if LANG_CXX11
AuxillaryParseTableField() = default;
#else
AuxillaryParseTableField() { }
#endif
PROTOBUF_CONSTEXPR AuxillaryParseTableField(
AuxillaryParseTableField::enum_aux e) : enums(e) {}
PROTOBUF_CONSTEXPR AuxillaryParseTableField(
AuxillaryParseTableField::message_aux m) : messages(m) {}
PROTOBUF_CONSTEXPR AuxillaryParseTableField(
AuxillaryParseTableField::string_aux s) : strings(s) {}
PROTOBUF_CONSTEXPR AuxillaryParseTableField(
AuxillaryParseTableField::map_aux m)
: maps(m) {}
};
struct ParseTable {
const ParseTableField* fields;
const AuxiliaryParseTableField* aux;
const AuxillaryParseTableField* aux;
int max_field_number;
// TODO(ckennelly): Do something with this padding.
// TODO(ckennelly): Vet these for sign extension.
int64_t has_bits_offset;
int64_t oneof_case_offset;
int64_t extension_offset;
int64_t arena_offset;
int64 has_bits_offset;
int64 oneof_case_offset;
int64 extension_offset;
int64 arena_offset;
// ExplicitlyInitialized<T> -> T requires a reinterpret_cast, which prevents
// the tables from being constructed as a constexpr. We use void to avoid
@@ -203,149 +178,42 @@ struct ParseTable {
bool unknown_field_set;
};
// TODO(jhen): Remove the __NVCC__ check when we get a version of nvcc that
// supports these checks.
#if LANG_CXX11 && !defined(__NVCC__)
static_assert(sizeof(ParseTableField) <= 16, "ParseTableField is too large");
// The tables must be composed of POD components to ensure link-time
// initialization.
static_assert(std::is_standard_layout<ParseTableField>::value, "");
static_assert(std::is_trivial<ParseTableField>::value, "");
static_assert(std::is_standard_layout<AuxiliaryParseTableField>::value, "");
static_assert(std::is_trivial<AuxiliaryParseTableField>::value, "");
static_assert(
std::is_standard_layout<AuxiliaryParseTableField::enum_aux>::value, "");
static_assert(std::is_trivial<AuxiliaryParseTableField::enum_aux>::value, "");
static_assert(
std::is_standard_layout<AuxiliaryParseTableField::message_aux>::value, "");
static_assert(std::is_trivial<AuxiliaryParseTableField::message_aux>::value,
"");
static_assert(
std::is_standard_layout<AuxiliaryParseTableField::string_aux>::value, "");
static_assert(std::is_trivial<AuxiliaryParseTableField::string_aux>::value, "");
static_assert(std::is_standard_layout<ParseTable>::value, "");
static_assert(std::is_trivial<ParseTable>::value, "");
static_assert(std::is_pod<ParseTableField>::value, "");
static_assert(std::is_pod<AuxillaryParseTableField>::value, "");
static_assert(std::is_pod<AuxillaryParseTableField::enum_aux>::value, "");
static_assert(std::is_pod<AuxillaryParseTableField::message_aux>::value, "");
static_assert(std::is_pod<AuxillaryParseTableField::string_aux>::value, "");
static_assert(std::is_pod<ParseTable>::value, "");
#endif
// TODO(ckennelly): Consolidate these implementations into a single one, using
// dynamic dispatch to the appropriate unknown field handler.
bool MergePartialFromCodedStream(MessageLite* msg, const ParseTable& table,
io::CodedInputStream* input);
bool MergePartialFromCodedStreamLite(MessageLite* msg, const ParseTable& table,
io::CodedInputStream* input);
io::CodedInputStream* input);
template <typename Entry>
bool ParseMap(io::CodedInputStream* input, void* map_field) {
typedef typename MapEntryToMapField<Entry>::MapFieldType MapFieldType;
typedef Map<typename Entry::EntryKeyType, typename Entry::EntryValueType>
typedef google::protobuf::Map<typename Entry::EntryKeyType,
typename Entry::EntryValueType>
MapType;
typedef typename Entry::template Parser<MapFieldType, MapType> ParserType;
ParserType parser(static_cast<MapFieldType*>(map_field));
return WireFormatLite::ReadMessageNoVirtual(input, &parser);
}
struct SerializationTable {
int num_fields;
const FieldMetadata* field_table;
};
PROTOBUF_EXPORT void SerializeInternal(const uint8_t* base,
const FieldMetadata* table,
int32_t num_fields,
io::CodedOutputStream* output);
inline void TableSerialize(const MessageLite& msg,
const SerializationTable* table,
io::CodedOutputStream* output) {
const FieldMetadata* field_table = table->field_table;
int num_fields = table->num_fields - 1;
const uint8_t* base = reinterpret_cast<const uint8_t*>(&msg);
// TODO(gerbens) This skips the first test if we could use the fast
// array serialization path, we should make this
// int cached_size =
// *reinterpret_cast<const int32_t*>(base + field_table->offset);
// SerializeWithCachedSize(msg, field_table + 1, num_fields, cached_size, ...)
// But we keep conformance with the old way for now.
SerializeInternal(base, field_table + 1, num_fields, output);
}
PROTOBUF_EXPORT uint8_t* SerializeInternalToArray(const uint8_t* base,
const FieldMetadata* table,
int32_t num_fields,
bool is_deterministic,
uint8_t* buffer);
inline uint8_t* TableSerializeToArray(const MessageLite& msg,
const SerializationTable* table,
bool is_deterministic, uint8_t* buffer) {
const uint8_t* base = reinterpret_cast<const uint8_t*>(&msg);
const FieldMetadata* field_table = table->field_table + 1;
int num_fields = table->num_fields - 1;
return SerializeInternalToArray(base, field_table, num_fields,
is_deterministic, buffer);
}
template <typename T>
struct CompareHelper {
bool operator()(const T& a, const T& b) const { return a < b; }
};
template <>
struct CompareHelper<ArenaStringPtr> {
bool operator()(const ArenaStringPtr& a, const ArenaStringPtr& b) const {
return a.Get() < b.Get();
}
};
struct CompareMapKey {
template <typename T>
bool operator()(const MapEntryHelper<T>& a,
const MapEntryHelper<T>& b) const {
return Compare(a.key_, b.key_);
}
template <typename T>
bool Compare(const T& a, const T& b) const {
return CompareHelper<T>()(a, b);
}
};
template <typename MapFieldType, const SerializationTable* table>
void MapFieldSerializer(const uint8_t* base, uint32_t offset, uint32_t tag,
uint32_t has_offset, io::CodedOutputStream* output) {
typedef MapEntryHelper<typename MapFieldType::EntryTypeTrait> Entry;
typedef typename MapFieldType::MapType::const_iterator Iter;
const MapFieldType& map_field =
*reinterpret_cast<const MapFieldType*>(base + offset);
const SerializationTable* t =
table +
has_offset; // has_offset is overloaded for maps to mean table offset
if (!output->IsSerializationDeterministic()) {
for (Iter it = map_field.GetMap().begin(); it != map_field.GetMap().end();
++it) {
Entry map_entry(*it);
output->WriteVarint32(tag);
output->WriteVarint32(map_entry._cached_size_);
SerializeInternal(reinterpret_cast<const uint8_t*>(&map_entry),
t->field_table, t->num_fields, output);
}
} else {
std::vector<Entry> v;
for (Iter it = map_field.GetMap().begin(); it != map_field.GetMap().end();
++it) {
v.push_back(Entry(*it));
}
std::sort(v.begin(), v.end(), CompareMapKey());
for (int i = 0; i < v.size(); i++) {
output->WriteVarint32(tag);
output->WriteVarint32(v[i]._cached_size_);
SerializeInternal(reinterpret_cast<const uint8_t*>(&v[i]), t->field_table,
t->num_fields, output);
}
}
return ::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(input,
&parser);
}
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_H__
@@ -0,0 +1,109 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <google/protobuf/generated_message_table_driven_lite.h>
#include <google/protobuf/stubs/type_traits.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/metadata_lite.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/wire_format_lite_inl.h>
namespace google {
namespace protobuf {
namespace internal {
namespace {
string* MutableUnknownFields(MessageLite* msg, int64 arena_offset) {
return Raw<InternalMetadataWithArenaLite>(msg, arena_offset)
->mutable_unknown_fields();
}
struct UnknownFieldHandlerLite {
static bool Skip(MessageLite* msg, const ParseTable& table,
io::CodedInputStream* input,
int tag) {
GOOGLE_DCHECK(!table.unknown_field_set);
::google::protobuf::io::StringOutputStream unknown_fields_string(
MutableUnknownFields(msg, table.arena_offset));
::google::protobuf::io::CodedOutputStream unknown_fields_stream(
&unknown_fields_string, false);
return ::google::protobuf::internal::WireFormatLite::SkipField(
input, tag, &unknown_fields_stream);
}
static void Varint(MessageLite* msg, const ParseTable& table,
int tag, int value) {
GOOGLE_DCHECK(!table.unknown_field_set);
::google::protobuf::io::StringOutputStream unknown_fields_string(
MutableUnknownFields(msg, table.arena_offset));
::google::protobuf::io::CodedOutputStream unknown_fields_stream(
&unknown_fields_string, false);
unknown_fields_stream.WriteVarint32(tag);
unknown_fields_stream.WriteVarint32(value);
}
static bool ParseExtension(
MessageLite* msg, const ParseTable& table,
io::CodedInputStream* input, int tag) {
ExtensionSet* extensions = GetExtensionSet(msg, table.extension_offset);
if (extensions == NULL) {
return false;
}
const MessageLite* prototype = table.default_instance();
GOOGLE_DCHECK(!table.unknown_field_set);
::google::protobuf::io::StringOutputStream unknown_fields_string(
MutableUnknownFields(msg, table.arena_offset));
::google::protobuf::io::CodedOutputStream unknown_fields_stream(
&unknown_fields_string, false);
return extensions->ParseField(
tag, input, prototype, &unknown_fields_stream);
}
};
} // namespace
bool MergePartialFromCodedStreamLite(
MessageLite* msg, const ParseTable& table, io::CodedInputStream* input) {
return MergePartialFromCodedStreamImpl<UnknownFieldHandlerLite,
InternalMetadataWithArenaLite>(
msg, table, input);
}
} // namespace internal
} // namespace protobuf
} // namespace google
@@ -0,0 +1,823 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_LITE_H__
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_LITE_H__
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/stubs/type_traits.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/metadata_lite.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/wire_format_lite_inl.h>
namespace google {
namespace protobuf {
namespace internal {
enum StringType {
StringType_STRING = 0,
StringType_CORD = 1,
StringType_STRING_PIECE = 2
};
// Logically a superset of StringType, consisting of all field types that
// require special initialization.
enum ProcessingType {
ProcessingType_STRING = 0,
ProcessingType_CORD = 1,
ProcessingType_STRING_PIECE = 2,
ProcessingType_MESSAGE = 3
};
enum Cardinality {
Cardinality_SINGULAR = 0,
Cardinality_REPEATED = 1,
Cardinality_ONEOF = 3
};
template <typename Type>
inline Type* Raw(MessageLite* msg, int64 offset) {
return reinterpret_cast<Type*>(reinterpret_cast<uint8*>(msg) + offset);
}
template <typename Type>
inline const Type* Raw(const MessageLite* msg, int64 offset) {
return reinterpret_cast<const Type*>(reinterpret_cast<const uint8*>(msg) +
offset);
}
template <typename InternalMetadata>
inline Arena* GetArena(MessageLite* msg, int64 arena_offset) {
if (GOOGLE_PREDICT_FALSE(arena_offset == -1)) {
return NULL;
}
return Raw<InternalMetadata>(msg, arena_offset)->arena();
}
inline ExtensionSet* GetExtensionSet(MessageLite* msg, int64 extension_offset) {
if (extension_offset == -1) {
return NULL;
}
return Raw<ExtensionSet>(msg, extension_offset);
}
template <typename Type>
inline Type* AddField(MessageLite* msg, int64 offset) {
#if LANG_CXX11
static_assert(has_trivial_copy<Type>::value,
"Do not assign");
#endif
google::protobuf::RepeatedField<Type>* repeated =
Raw<google::protobuf::RepeatedField<Type> >(msg, offset);
return repeated->Add();
}
template <>
inline string* AddField<string>(MessageLite* msg, int64 offset) {
google::protobuf::RepeatedPtrField<string>* repeated =
Raw<google::protobuf::RepeatedPtrField<string> >(msg, offset);
return repeated->Add();
}
template <typename Type>
inline void AddField(MessageLite* msg, int64 offset, Type value) {
#if LANG_CXX11
static_assert(has_trivial_copy<Type>::value,
"Do not assign");
#endif
*AddField<Type>(msg, offset) = value;
}
inline void SetBit(uint32* has_bits, uint32 has_bit_index) {
GOOGLE_DCHECK(has_bits != NULL);
uint32 mask = static_cast<uint32>(1u) << (has_bit_index % 32);
has_bits[has_bit_index / 32u] |= mask;
}
template <typename Type>
inline Type* MutableField(MessageLite* msg, uint32* has_bits,
uint32 has_bit_index, int64 offset) {
SetBit(has_bits, has_bit_index);
return Raw<Type>(msg, offset);
}
template <typename Type>
inline void SetField(MessageLite* msg, uint32* has_bits, uint32 has_bit_index,
int64 offset, Type value) {
#if LANG_CXX11
static_assert(has_trivial_copy<Type>::value,
"Do not assign");
#endif
*MutableField<Type>(msg, has_bits, has_bit_index, offset) = value;
}
template <typename Type>
inline void SetOneofField(MessageLite* msg, uint32* oneof_case,
uint32 oneof_case_index, int64 offset,
int field_number, Type value) {
oneof_case[oneof_case_index] = field_number;
*Raw<Type>(msg, offset) = value;
}
// Clears a oneof field. The field argument should correspond to the particular
// field that is currently set in the oneof.
inline void ClearOneofField(const ParseTableField& field, Arena* arena,
MessageLite* msg) {
switch (field.processing_type & kTypeMask) {
case WireFormatLite::TYPE_MESSAGE:
if (arena == NULL) {
delete *Raw<MessageLite*>(msg, field.offset);
}
break;
case WireFormatLite::TYPE_STRING:
case WireFormatLite::TYPE_BYTES:
Raw<ArenaStringPtr>(msg, field.offset)
->Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
break;
default:
// No cleanup needed.
break;
}
}
// Clears and reinitializes a oneof field as necessary, in preparation for
// parsing a new value with type field_type and field number field_number.
//
// Note: the oneof_case argument should point directly to the _oneof_case_
// element corresponding to this particular oneof, not to the beginning of the
// _oneof_case_ array.
template <ProcessingType field_type>
inline void ResetOneofField(const ParseTable& table, int field_number,
Arena* arena, MessageLite* msg, uint32* oneof_case,
int64 offset, const void* default_ptr) {
if (*oneof_case == field_number) {
// The oneof is already set to the right type, so there is no need to clear
// it.
return;
}
if (*oneof_case != 0) {
ClearOneofField(table.fields[*oneof_case], arena, msg);
}
*oneof_case = field_number;
switch (field_type) {
case ProcessingType_STRING:
Raw<ArenaStringPtr>(msg, offset)
->UnsafeSetDefault(static_cast<const string*>(default_ptr));
break;
case ProcessingType_MESSAGE:
MessageLite** submessage = Raw<MessageLite*>(msg, offset);
const MessageLite* prototype =
table.aux[field_number].messages.default_message();
*submessage = prototype->New(arena);
break;
}
}
template <Cardinality cardinality, bool validate, StringType ctype>
static inline bool HandleString(io::CodedInputStream* input, MessageLite* msg,
Arena* arena, uint32* has_bits,
uint32 has_bit_index, int64 offset,
const void* default_ptr,
const char* field_name) {
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
const char* sdata;
size_t size;
#endif
string* value;
switch (cardinality) {
case Cardinality_SINGULAR:
// TODO(ckennelly): Is this optimal?
value =
MutableField<ArenaStringPtr>(msg, has_bits, has_bit_index, offset)
->Mutable(static_cast<const string*>(default_ptr), arena);
break;
case Cardinality_REPEATED:
value = AddField<string>(msg, offset);
break;
case Cardinality_ONEOF:
value = Raw<ArenaStringPtr>(msg, offset)
->Mutable(static_cast<const string*>(default_ptr), arena);
break;
}
GOOGLE_DCHECK(value != NULL);
if (GOOGLE_PREDICT_FALSE(!WireFormatLite::ReadString(input, value))) {
return false;
}
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
sdata = value->data();
size = value->size();
#endif
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
if (validate) {
WireFormatLite::VerifyUtf8String(sdata, size, WireFormatLite::PARSE,
field_name);
}
#endif
return true;
}
template <typename UnknownFieldHandler, typename InternalMetadata,
Cardinality cardinality>
inline bool HandleEnum(const ParseTable& table, io::CodedInputStream* input,
MessageLite* msg, uint32* presence,
uint32 presence_index, int64 offset, uint32 tag,
int field_number) {
int value;
if (GOOGLE_PREDICT_FALSE(
(!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>(
input, &value)))) {
return false;
}
AuxillaryParseTableField::EnumValidator validator =
table.aux[field_number].enums.validator;
if (validator(value)) {
switch (cardinality) {
case Cardinality_SINGULAR:
SetField(msg, presence, presence_index, offset, value);
break;
case Cardinality_REPEATED:
AddField(msg, offset, value);
break;
case Cardinality_ONEOF:
ClearOneofField(table.fields[presence[presence_index]],
GetArena<InternalMetadata>(msg, table.arena_offset),
msg);
SetOneofField(msg, presence, presence_index, offset, field_number,
value);
break;
}
} else {
UnknownFieldHandler::Varint(msg, table, tag, value);
}
return true;
}
// RepeatedMessageTypeHandler allows us to operate on RepeatedPtrField fields
// without instantiating the specific template.
class RepeatedMessageTypeHandler {
public:
typedef MessageLite Type;
static Arena* GetArena(Type* t) { return t->GetArena(); }
static void* GetMaybeArenaPointer(Type* t) {
return t->GetMaybeArenaPointer();
}
static inline Type* NewFromPrototype(const Type* prototype,
Arena* arena = NULL) {
return prototype->New(arena);
}
static void Delete(Type* t, Arena* arena = NULL) {
if (arena == NULL) {
delete t;
}
}
};
inline bool ReadGroup(int field_number, io::CodedInputStream* input,
MessageLite* value) {
if (GOOGLE_PREDICT_FALSE(!input->IncrementRecursionDepth())) {
return false;
}
if (GOOGLE_PREDICT_FALSE(!value->MergePartialFromCodedStream(input))) {
return false;
}
input->DecrementRecursionDepth();
// Make sure the last thing read was an end tag for this group.
if (GOOGLE_PREDICT_FALSE(!input->LastTagWas(WireFormatLite::MakeTag(
field_number, WireFormatLite::WIRETYPE_END_GROUP)))) {
return false;
}
return true;
}
inline bool ReadMessage(io::CodedInputStream* input, MessageLite* value) {
int length;
if (GOOGLE_PREDICT_FALSE(!input->ReadVarintSizeAsInt(&length))) {
return false;
}
std::pair<io::CodedInputStream::Limit, int> p =
input->IncrementRecursionDepthAndPushLimit(length);
if (GOOGLE_PREDICT_FALSE(p.second < 0 ||
!value->MergePartialFromCodedStream(input))) {
return false;
}
// Make sure that parsing stopped when the limit was hit, not at an endgroup
// tag.
return input->DecrementRecursionDepthAndPopLimit(p.first);
}
class MergePartialFromCodedStreamHelper {
public:
static MessageLite* Add(RepeatedPtrFieldBase* field,
const MessageLite* prototype) {
return field->Add<RepeatedMessageTypeHandler>(
const_cast<MessageLite*>(prototype));
}
};
template <typename UnknownFieldHandler, typename InternalMetadata>
bool MergePartialFromCodedStreamImpl(MessageLite* msg, const ParseTable& table,
io::CodedInputStream* input) {
// We require that has_bits are present, as to avoid having to check for them
// for every field.
//
// TODO(ckennelly): Make this a compile-time parameter with templates.
GOOGLE_DCHECK_GE(table.has_bits_offset, 0);
uint32* has_bits = Raw<uint32>(msg, table.has_bits_offset);
GOOGLE_DCHECK(has_bits != NULL);
while (true) {
uint32 tag = input->ReadTag();
const WireFormatLite::WireType wire_type =
WireFormatLite::GetTagWireType(tag);
const int field_number = WireFormatLite::GetTagFieldNumber(tag);
if (field_number > table.max_field_number) {
// check for possible extensions
if (UnknownFieldHandler::ParseExtension(msg, table, input, tag)) {
// successfully parsed
continue;
}
if (GOOGLE_PREDICT_FALSE(!UnknownFieldHandler::Skip(msg, table, input, tag))) {
return false;
}
continue;
}
// We implicitly verify that data points to a valid field as we check the
// wire types. Entries in table.fields[i] that do not correspond to valid
// field numbers have their normal_wiretype and packed_wiretype fields set
// with the kInvalidMask value. As wire_type cannot take on that value, we
// will never match.
const ParseTableField* data = table.fields + field_number;
// TODO(ckennelly): Avoid sign extension
const int64 presence_index = data->presence_index;
const int64 offset = data->offset;
const unsigned char processing_type = data->processing_type;
if (data->normal_wiretype == static_cast<unsigned char>(wire_type)) {
// TODO(ckennelly): Use a computed goto on GCC/LLVM or otherwise eliminate
// the bounds check on processing_type.
switch (processing_type) {
#define HANDLE_TYPE(TYPE, CPPTYPE) \
case (WireFormatLite::TYPE_##TYPE): { \
CPPTYPE value; \
if (GOOGLE_PREDICT_FALSE( \
(!WireFormatLite::ReadPrimitive< \
CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)))) { \
return false; \
} \
SetField(msg, has_bits, presence_index, offset, value); \
break; \
} \
case (WireFormatLite::TYPE_##TYPE) | kRepeatedMask: { \
google::protobuf::RepeatedField<CPPTYPE>* values = \
Raw<google::protobuf::RepeatedField<CPPTYPE> >(msg, offset); \
if (GOOGLE_PREDICT_FALSE((!WireFormatLite::ReadRepeatedPrimitive< \
CPPTYPE, WireFormatLite::TYPE_##TYPE>( \
data->tag_size, tag, input, values)))) { \
return false; \
} \
break; \
} \
case (WireFormatLite::TYPE_##TYPE) | kOneofMask: { \
uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset); \
CPPTYPE value; \
if (GOOGLE_PREDICT_FALSE( \
(!WireFormatLite::ReadPrimitive< \
CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)))) { \
return false; \
} \
ClearOneofField(table.fields[oneof_case[presence_index]], \
GetArena<InternalMetadata>(msg, table.arena_offset), msg); \
SetOneofField(msg, oneof_case, presence_index, offset, field_number, \
value); \
break; \
}
HANDLE_TYPE(INT32, int32)
HANDLE_TYPE(INT64, int64)
HANDLE_TYPE(SINT32, int32)
HANDLE_TYPE(SINT64, int64)
HANDLE_TYPE(UINT32, uint32)
HANDLE_TYPE(UINT64, uint64)
HANDLE_TYPE(FIXED32, uint32)
HANDLE_TYPE(FIXED64, uint64)
HANDLE_TYPE(SFIXED32, int32)
HANDLE_TYPE(SFIXED64, int64)
HANDLE_TYPE(FLOAT, float)
HANDLE_TYPE(DOUBLE, double)
HANDLE_TYPE(BOOL, bool)
#undef HANDLE_TYPE
case WireFormatLite::TYPE_BYTES:
#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case WireFormatLite::TYPE_STRING:
#endif
{
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
const void* default_ptr = table.aux[field_number].strings.default_ptr;
if (GOOGLE_PREDICT_FALSE((
!HandleString<Cardinality_SINGULAR, false, StringType_STRING>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, NULL)))) {
return false;
}
break;
}
case WireFormatLite::TYPE_BYTES | kOneofMask:
#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case WireFormatLite::TYPE_STRING | kOneofMask:
#endif
{
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset);
const void* default_ptr = table.aux[field_number].strings.default_ptr;
ResetOneofField<ProcessingType_STRING>(
table, field_number, arena, msg, oneof_case + presence_index,
offset, default_ptr);
if (GOOGLE_PREDICT_FALSE(
(!HandleString<Cardinality_ONEOF, false, StringType_STRING>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, NULL)))) {
return false;
}
break;
}
case (WireFormatLite::TYPE_BYTES) | kRepeatedMask:
#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case (WireFormatLite::TYPE_STRING) | kRepeatedMask:
#endif
{
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
const void* default_ptr =
table.aux[field_number].strings.default_ptr;
if (GOOGLE_PREDICT_FALSE((
!HandleString<Cardinality_REPEATED, false, StringType_STRING>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, NULL)))) {
return false;
}
break;
}
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case (WireFormatLite::TYPE_STRING): {
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
const void* default_ptr = table.aux[field_number].strings.default_ptr;
const char* field_name = table.aux[field_number].strings.field_name;
if (GOOGLE_PREDICT_FALSE(
(!HandleString<Cardinality_SINGULAR, true, StringType_STRING>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, field_name)))) {
return false;
}
break;
}
case (WireFormatLite::TYPE_STRING) | kRepeatedMask: {
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
const void* default_ptr = table.aux[field_number].strings.default_ptr;
const char* field_name = table.aux[field_number].strings.field_name;
if (GOOGLE_PREDICT_FALSE(
(!HandleString<Cardinality_REPEATED, true, StringType_STRING>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, field_name)))) {
return false;
}
break;
}
case (WireFormatLite::TYPE_STRING) | kOneofMask: {
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset);
const void* default_ptr = table.aux[field_number].strings.default_ptr;
const char* field_name = table.aux[field_number].strings.field_name;
ResetOneofField<ProcessingType_STRING>(
table, field_number, arena, msg, oneof_case + presence_index,
offset, default_ptr);
if (GOOGLE_PREDICT_FALSE(
(!HandleString<Cardinality_ONEOF, true, StringType_STRING>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, field_name)))) {
return false;
}
break;
}
#endif
case WireFormatLite::TYPE_ENUM: {
if (GOOGLE_PREDICT_FALSE((!HandleEnum<UnknownFieldHandler, InternalMetadata,
Cardinality_SINGULAR>(
table, input, msg, has_bits, presence_index, offset, tag,
field_number)))) {
return false;
}
break;
}
case WireFormatLite::TYPE_ENUM | kRepeatedMask: {
if (GOOGLE_PREDICT_FALSE((!HandleEnum<UnknownFieldHandler, InternalMetadata,
Cardinality_REPEATED>(
table, input, msg, has_bits, presence_index, offset, tag,
field_number)))) {
return false;
}
break;
}
case WireFormatLite::TYPE_ENUM | kOneofMask: {
uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset);
if (GOOGLE_PREDICT_FALSE((!HandleEnum<UnknownFieldHandler, InternalMetadata,
Cardinality_ONEOF>(
table, input, msg, oneof_case, presence_index, offset, tag,
field_number)))) {
return false;
}
break;
}
case WireFormatLite::TYPE_GROUP: {
MessageLite** submsg_holder =
MutableField<MessageLite*>(msg, has_bits, presence_index, offset);
MessageLite* submsg = *submsg_holder;
if (submsg == NULL) {
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
const MessageLite* prototype =
table.aux[field_number].messages.default_message();
submsg = prototype->New(arena);
*submsg_holder = submsg;
}
if (GOOGLE_PREDICT_FALSE(!WireFormatLite::ReadGroup(
field_number, input, submsg))) {
return false;
}
break;
}
case WireFormatLite::TYPE_GROUP | kRepeatedMask: {
RepeatedPtrFieldBase* field = Raw<RepeatedPtrFieldBase>(msg, offset);
const MessageLite* prototype =
table.aux[field_number].messages.default_message();
GOOGLE_DCHECK(prototype != NULL);
MessageLite* submsg =
MergePartialFromCodedStreamHelper::Add(field, prototype);
if (GOOGLE_PREDICT_FALSE(!WireFormatLite::ReadGroup(
field_number, input, submsg))) {
return false;
}
break;
}
case WireFormatLite::TYPE_MESSAGE: {
MessageLite** submsg_holder =
MutableField<MessageLite*>(msg, has_bits, presence_index, offset);
MessageLite* submsg = *submsg_holder;
if (submsg == NULL) {
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
const MessageLite* prototype =
table.aux[field_number].messages.default_message();
submsg = prototype->New(arena);
*submsg_holder = submsg;
}
if (GOOGLE_PREDICT_FALSE(!WireFormatLite::ReadMessage(input, submsg))) {
return false;
}
break;
}
// TODO(ckennelly): Adapt ReadMessageNoVirtualNoRecursionDepth and
// manage input->IncrementRecursionDepth() here.
case WireFormatLite::TYPE_MESSAGE | kRepeatedMask: {
RepeatedPtrFieldBase* field = Raw<RepeatedPtrFieldBase>(msg, offset);
const MessageLite* prototype =
table.aux[field_number].messages.default_message();
GOOGLE_DCHECK(prototype != NULL);
MessageLite* submsg =
MergePartialFromCodedStreamHelper::Add(field, prototype);
if (GOOGLE_PREDICT_FALSE(!WireFormatLite::ReadMessage(input, submsg))) {
return false;
}
break;
}
case WireFormatLite::TYPE_MESSAGE | kOneofMask: {
Arena* const arena =
GetArena<InternalMetadata>(msg, table.arena_offset);
uint32* oneof_case = Raw<uint32>(msg, table.oneof_case_offset);
MessageLite** submsg_holder = Raw<MessageLite*>(msg, offset);
ResetOneofField<ProcessingType_MESSAGE>(
table, field_number, arena, msg, oneof_case + presence_index,
offset, NULL);
MessageLite* submsg = *submsg_holder;
if (GOOGLE_PREDICT_FALSE(!WireFormatLite::ReadMessage(input, submsg))) {
return false;
}
break;
}
case TYPE_MAP: {
if (GOOGLE_PREDICT_FALSE(!(*table.aux[field_number].maps.parse_map)(
input, Raw<void>(msg, offset)))) {
return false;
}
break;
}
case 0: {
// Done.
return true;
}
default:
break;
}
} else if (data->packed_wiretype == static_cast<unsigned char>(wire_type)) {
// Non-packable fields have their packed_wiretype masked with
// kNotPackedMask, which is impossible to match here.
GOOGLE_DCHECK(processing_type & kRepeatedMask);
GOOGLE_DCHECK_NE(processing_type, kRepeatedMask);
GOOGLE_DCHECK_EQ(0, processing_type & kOneofMask);
// TODO(ckennelly): Use a computed goto on GCC/LLVM.
//
// Mask out kRepeatedMask bit, allowing the jump table to be smaller.
switch (static_cast<WireFormatLite::FieldType>(
processing_type ^ kRepeatedMask)) {
#define HANDLE_PACKED_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD) \
case WireFormatLite::TYPE_##TYPE: { \
google::protobuf::RepeatedField<CPPTYPE>* values = \
Raw<google::protobuf::RepeatedField<CPPTYPE> >(msg, offset); \
if (GOOGLE_PREDICT_FALSE( \
(!WireFormatLite::ReadPackedPrimitive< \
CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, values)))) { \
return false; \
} \
break; \
}
HANDLE_PACKED_TYPE(INT32, int32, Int32)
HANDLE_PACKED_TYPE(INT64, int64, Int64)
HANDLE_PACKED_TYPE(SINT32, int32, Int32)
HANDLE_PACKED_TYPE(SINT64, int64, Int64)
HANDLE_PACKED_TYPE(UINT32, uint32, UInt32)
HANDLE_PACKED_TYPE(UINT64, uint64, UInt64)
HANDLE_PACKED_TYPE(FIXED32, uint32, UInt32)
HANDLE_PACKED_TYPE(FIXED64, uint64, UInt64)
HANDLE_PACKED_TYPE(SFIXED32, int32, Int32)
HANDLE_PACKED_TYPE(SFIXED64, int64, Int64)
HANDLE_PACKED_TYPE(FLOAT, float, Float)
HANDLE_PACKED_TYPE(DOUBLE, double, Double)
HANDLE_PACKED_TYPE(BOOL, bool, Bool)
#undef HANDLE_PACKED_TYPE
case WireFormatLite::TYPE_ENUM: {
// To avoid unnecessarily calling MutableUnknownFields (which mutates
// InternalMetadataWithArena) when all inputs in the repeated series
// are valid, we implement our own parser rather than call
// WireFormat::ReadPackedEnumPreserveUnknowns.
uint32 length;
if (GOOGLE_PREDICT_FALSE(!input->ReadVarint32(&length))) {
return false;
}
AuxillaryParseTableField::EnumValidator validator =
table.aux[field_number].enums.validator;
google::protobuf::RepeatedField<int>* values =
Raw<google::protobuf::RepeatedField<int> >(msg, offset);
io::CodedInputStream::Limit limit = input->PushLimit(length);
while (input->BytesUntilLimit() > 0) {
int value;
if (GOOGLE_PREDICT_FALSE(
(!google::protobuf::internal::WireFormatLite::ReadPrimitive<
int, WireFormatLite::TYPE_ENUM>(input, &value)))) {
return false;
}
if (validator(value)) {
values->Add(value);
} else {
// TODO(ckennelly): Consider caching here.
UnknownFieldHandler::Varint(msg, table, tag, value);
}
}
input->PopLimit(limit);
break;
}
case WireFormatLite::TYPE_STRING:
case WireFormatLite::TYPE_GROUP:
case WireFormatLite::TYPE_MESSAGE:
case WireFormatLite::TYPE_BYTES:
GOOGLE_DCHECK(false);
return false;
default:
break;
}
} else {
if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) {
// Must be the end of the message.
return true;
}
// check for possible extensions
if (UnknownFieldHandler::ParseExtension(msg, table, input, tag)) {
// successfully parsed
continue;
}
// process unknown field.
if (GOOGLE_PREDICT_FALSE(!UnknownFieldHandler::Skip(msg, table, input, tag))) {
return false;
}
}
}
}
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_LITE_H__
@@ -1,139 +0,0 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This file contains declarations needed in generated headers for messages
// that use tail-call table parsing. Everything in this file is for internal
// use only.
#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_DECL_H__
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_DECL_H__
#include <cstdint>
#include <type_traits>
#include <google/protobuf/parse_context.h>
#include <google/protobuf/message_lite.h>
// Must come last:
#include <google/protobuf/port_def.inc>
namespace google {
namespace protobuf {
namespace internal {
// Additional information about this field:
struct TcFieldData {
constexpr TcFieldData() : data(0) {}
constexpr TcFieldData(uint16_t coded_tag, uint8_t hasbit_idx, uint16_t offset)
: data(static_cast<uint64_t>(offset) << 48 |
static_cast<uint64_t>(hasbit_idx) << 16 | coded_tag) {}
template <typename TagType = uint16_t>
TagType coded_tag() const {
return static_cast<TagType>(data);
}
uint8_t hasbit_idx() const { return static_cast<uint8_t>(data >> 16); }
uint16_t offset() const { return static_cast<uint16_t>(data >> 48); }
uint64_t data;
};
struct TcParseTableBase;
// TailCallParseFunc is the function pointer type used in the tailcall table.
typedef const char* (*TailCallParseFunc)(PROTOBUF_TC_PARAM_DECL);
#if defined(_MSC_VER) && !defined(_WIN64)
#pragma warning(push)
// TcParseTableBase is intentionally overaligned on 32 bit targets.
#pragma warning(disable : 4324)
#endif
// Base class for message-level table with info for the tail-call parser.
struct alignas(uint64_t) TcParseTableBase {
// Common attributes for message layout:
uint16_t has_bits_offset;
uint16_t extension_offset;
uint32_t extension_range_low;
uint32_t extension_range_high;
uint8_t fast_idx_mask;
uint8_t reserved;
uint16_t num_fields;
const MessageLite* default_instance;
// Handler for fields which are not handled by table dispatch.
TailCallParseFunc fallback;
// Table entry for fast-path tailcall dispatch handling.
struct FastFieldEntry {
// Target function for dispatch:
TailCallParseFunc target;
// Field data used during parse:
TcFieldData bits;
};
// There is always at least one table entry.
const FastFieldEntry* fast_entry(size_t idx) const {
return reinterpret_cast<const FastFieldEntry*>(this + 1) + idx;
}
};
#if defined(_MSC_VER) && !defined(_WIN64)
#pragma warning(pop)
#endif
static_assert(sizeof(TcParseTableBase::FastFieldEntry) <= 16,
"Field entry is too big.");
template <size_t kFastTableSizeLog2>
struct TcParseTable {
TcParseTableBase header;
// Entries for each field.
//
// Fields are indexed by the lowest bits of their field number. The field
// number is masked to fit inside the table. Note that the parsing logic
// generally calls `TailCallParseTableBase::table()` instead of accessing
// this field directly.
TcParseTableBase::FastFieldEntry entries[(1 << kFastTableSizeLog2)];
};
static_assert(std::is_standard_layout<TcParseTable<1>>::value,
"TcParseTable must be standard layout.");
static_assert(offsetof(TcParseTable<1>, entries) == sizeof(TcParseTableBase),
"Table entries must be laid out after TcParseTableBase.");
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_DECL_H__
@@ -1,302 +0,0 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_IMPL_H__
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_IMPL_H__
#include <cstdint>
#include <type_traits>
#include <google/protobuf/parse_context.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/generated_message_tctable_decl.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/metadata_lite.h>
#include <google/protobuf/port.h>
#include <google/protobuf/wire_format_lite.h>
// Must come last:
#include <google/protobuf/port_def.inc>
namespace google {
namespace protobuf {
class Message;
class UnknownFieldSet;
namespace internal {
// PROTOBUF_TC_PARAM_DECL are the parameters for tailcall functions, it is
// defined in port_def.inc.
//
// Note that this is performance sensitive: changing the parameters will change
// the registers used by the ABI calling convention, which subsequently affects
// register selection logic inside the function.
// PROTOBUF_TC_PARAM_PASS passes values to match PROTOBUF_TC_PARAM_DECL.
#define PROTOBUF_TC_PARAM_PASS msg, ptr, ctx, table, hasbits, data
// PROTOBUF_TC_PARSE_* decide which function is used to parse message-typed
// fields. The guard macros are defined in port_def.inc.
#if PROTOBUF_TC_STATIC_PARSE_SINGULAR1
#define PROTOBUF_TC_PARSE_SINGULAR1(MESSAGE) MESSAGE::Tct_ParseS1
#else
#define PROTOBUF_TC_PARSE_SINGULAR1(MESSAGE) \
::google::protobuf::internal::TcParser::SingularParseMessage<MESSAGE, uint8_t>
#endif // PROTOBUF_TC_STATIC_PARSE_SINGULAR1
#if PROTOBUF_TC_STATIC_PARSE_SINGULAR2
#define PROTOBUF_TC_PARSE_SINGULAR2(MESSAGE) MESSAGE::Tct_ParseS2
#else
#define PROTOBUF_TC_PARSE_SINGULAR2(MESSAGE) \
::google::protobuf::internal::TcParser::SingularParseMessage<MESSAGE, uint16_t>
#endif // PROTOBUF_TC_STATIC_PARSE_SINGULAR2
#if PROTOBUF_TC_STATIC_PARSE_REPEATED1
#define PROTOBUF_TC_PARSE_REPEATED1(MESSAGE) MESSAGE::Tct_ParseR1
#else
#define PROTOBUF_TC_PARSE_REPEATED1(MESSAGE) \
::google::protobuf::internal::TcParser::RepeatedParseMessage<MESSAGE, uint8_t>
#endif // PROTOBUF_TC_STATIC_PARSE_REPEATED1
#if PROTOBUF_TC_STATIC_PARSE_REPEATED2
#define PROTOBUF_TC_PARSE_REPEATED2(MESSAGE) MESSAGE::Tct_ParseR2
#else
#define PROTOBUF_TC_PARSE_REPEATED2(MESSAGE) \
::google::protobuf::internal::TcParser::RepeatedParseMessage<MESSAGE, uint16_t>
#endif // PROTOBUF_TC_STATIC_PARSE_REPEATED2
#ifndef NDEBUG
template <size_t align>
#ifndef _MSC_VER
[[noreturn]]
#endif
void AlignFail(uintptr_t address) {
GOOGLE_LOG(FATAL) << "Unaligned (" << align << ") access at " << address;
}
extern template void AlignFail<4>(uintptr_t);
extern template void AlignFail<8>(uintptr_t);
#endif
// TcParser implements most of the parsing logic for tailcall tables.
class TcParser final {
public:
static const char* GenericFallback(PROTOBUF_TC_PARAM_DECL);
static const char* GenericFallbackLite(PROTOBUF_TC_PARAM_DECL);
// Dispatch to the designated parse function
inline PROTOBUF_ALWAYS_INLINE static const char* TagDispatch(
PROTOBUF_TC_PARAM_DECL) {
const auto coded_tag = UnalignedLoad<uint16_t>(ptr);
const size_t idx = coded_tag & table->fast_idx_mask;
PROTOBUF_ASSUME((idx & 7) == 0);
auto* fast_entry = table->fast_entry(idx >> 3);
data = fast_entry->bits;
data.data ^= coded_tag;
PROTOBUF_MUSTTAIL return fast_entry->target(PROTOBUF_TC_PARAM_PASS);
}
// We can only safely call from field to next field if the call is optimized
// to a proper tail call. Otherwise we blow through stack. Clang and gcc
// reliably do this optimization in opt mode, but do not perform this in debug
// mode. Luckily the structure of the algorithm is such that it's always
// possible to just return and use the enclosing parse loop as a trampoline.
static const char* ToTagDispatch(PROTOBUF_TC_PARAM_DECL) {
constexpr bool always_return = !PROTOBUF_TAILCALL;
if (always_return || !ctx->DataAvailable(ptr)) {
PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
}
PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_PASS);
}
static const char* ParseLoop(MessageLite* msg, const char* ptr,
ParseContext* ctx,
const TcParseTableBase* table) {
ScopedArenaSwap saved(msg, ctx);
const uint32_t has_bits_offset = table->has_bits_offset;
while (!ctx->Done(&ptr)) {
uint64_t hasbits = 0;
if (has_bits_offset) hasbits = RefAt<uint32_t>(msg, has_bits_offset);
ptr = TagDispatch(msg, ptr, ctx, table, hasbits, {});
if (ptr == nullptr) break;
if (ctx->LastTag() != 1) break; // Ended on terminating tag
}
return ptr;
}
template <typename FieldType, typename TagType>
PROTOBUF_NOINLINE static const char* SingularParseMessage(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
return table->fallback(PROTOBUF_TC_PARAM_PASS);
}
ptr += sizeof(TagType);
hasbits |= (uint64_t{1} << data.hasbit_idx());
auto& field = RefAt<FieldType*>(msg, data.offset());
if (field == nullptr) {
auto arena = ctx->data().arena;
if (Arena::is_arena_constructable<FieldType>::value) {
field = Arena::CreateMessage<FieldType>(arena);
} else {
field = Arena::Create<FieldType>(arena);
}
}
SyncHasbits(msg, hasbits, table);
return ctx->ParseMessage(field, ptr);
}
template <typename FieldType, typename TagType>
PROTOBUF_NOINLINE static const char* RepeatedParseMessage(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
return table->fallback(PROTOBUF_TC_PARAM_PASS);
}
ptr += sizeof(TagType);
auto& field = RefAt<RepeatedPtrField<FieldType>>(msg, data.offset());
SyncHasbits(msg, hasbits, table);
ptr = ctx->ParseMessage(field.Add(), ptr);
return ptr;
}
template <typename LayoutType, typename TagType>
static const char* SingularFixed(PROTOBUF_TC_PARAM_DECL);
template <typename LayoutType, typename TagType>
static const char* RepeatedFixed(PROTOBUF_TC_PARAM_DECL);
template <typename LayoutType, typename TagType>
static const char* PackedFixed(PROTOBUF_TC_PARAM_DECL);
enum VarintDecode { kNoConversion = 0, kZigZag = 1 };
template <typename FieldType, typename TagType, VarintDecode zigzag>
static const char* SingularVarint(PROTOBUF_TC_PARAM_DECL);
template <typename FieldType, typename TagType, VarintDecode zigzag>
static const char* RepeatedVarint(PROTOBUF_TC_PARAM_DECL);
template <typename FieldType, typename TagType, VarintDecode zigzag>
static const char* PackedVarint(PROTOBUF_TC_PARAM_DECL);
enum Utf8Type { kNoUtf8 = 0, kUtf8 = 1, kUtf8ValidateOnly = 2 };
template <typename TagType, Utf8Type utf8>
static const char* SingularString(PROTOBUF_TC_PARAM_DECL);
template <typename TagType, Utf8Type utf8>
static const char* RepeatedString(PROTOBUF_TC_PARAM_DECL);
template <typename T>
static inline T& RefAt(void* x, size_t offset) {
T* target = reinterpret_cast<T*>(static_cast<char*>(x) + offset);
#ifndef NDEBUG
if (PROTOBUF_PREDICT_FALSE(
reinterpret_cast<uintptr_t>(target) % alignof(T) != 0)) {
AlignFail<alignof(T)>(reinterpret_cast<uintptr_t>(target));
}
#endif
return *target;
}
static inline PROTOBUF_ALWAYS_INLINE void SyncHasbits(
MessageLite* msg, uint64_t hasbits, const TcParseTableBase* table) {
const uint32_t has_bits_offset = table->has_bits_offset;
if (has_bits_offset) {
// Only the first 32 has-bits are updated. Nothing above those is stored,
// but e.g. messages without has-bits update the upper bits.
RefAt<uint32_t>(msg, has_bits_offset) = static_cast<uint32_t>(hasbits);
}
}
protected:
static inline PROTOBUF_ALWAYS_INLINE const char* ToParseLoop(
PROTOBUF_TC_PARAM_DECL) {
(void)data;
(void)ctx;
SyncHasbits(msg, hasbits, table);
return ptr;
}
static inline PROTOBUF_ALWAYS_INLINE const char* Error(
PROTOBUF_TC_PARAM_DECL) {
(void)data;
(void)ctx;
(void)ptr;
SyncHasbits(msg, hasbits, table);
return nullptr;
}
class ScopedArenaSwap final {
public:
ScopedArenaSwap(MessageLite* msg, ParseContext* ctx)
: ctx_(ctx), saved_(ctx->data().arena) {
ctx_->data().arena = msg->GetArenaForAllocation();
}
ScopedArenaSwap(const ScopedArenaSwap&) = delete;
~ScopedArenaSwap() { ctx_->data().arena = saved_; }
private:
ParseContext* const ctx_;
Arena* const saved_;
};
template <class MessageBaseT, class UnknownFieldsT>
static const char* GenericFallbackImpl(PROTOBUF_TC_PARAM_DECL) {
#define CHK_(x) \
if (PROTOBUF_PREDICT_FALSE(!(x))) return nullptr /* NOLINT */
SyncHasbits(msg, hasbits, table);
uint32_t tag;
ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
CHK_(ptr);
if ((tag & 7) == WireFormatLite::WIRETYPE_END_GROUP || tag == 0) {
ctx->SetLastTag(tag);
return ptr;
}
(void)data;
uint32_t num = tag >> 3;
if (table->extension_range_low <= num &&
num <= table->extension_range_high) {
return RefAt<ExtensionSet>(msg, table->extension_offset)
.ParseField(tag, ptr,
static_cast<const MessageBaseT*>(table->default_instance),
&msg->_internal_metadata_, ctx);
}
return UnknownFieldParse(
tag, msg->_internal_metadata_.mutable_unknown_fields<UnknownFieldsT>(),
ptr, ctx);
#undef CHK_
}
};
// Declare helper functions:
#include <google/protobuf/generated_message_tctable_impl.inc>
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_IMPL_H__
@@ -1,92 +0,0 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// clang-format off
#ifdef PROTOBUF_TCT_SOURCE
#define PROTOBUF_TCT_EXTERN
#else
#define PROTOBUF_TCT_EXTERN extern
#endif
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedFixed<uint64_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedFixed<uint32_t, uint8_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<uint64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<uint32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<int64_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<int32_t, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<bool, uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint8_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedFixed<uint64_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedFixed<uint32_t, uint16_t>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<uint64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<uint32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<int64_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<int32_t, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kZigZag>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint<bool, uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoConversion>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kNoUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString<uint16_t, ::PROTOBUF_NAMESPACE_ID::internal::TcParser::kUtf8ValidateOnly>(PROTOBUF_TC_PARAM_DECL);
#undef PROTOBUF_TCT_EXTERN
// clang-format on
+139 -188
View File
@@ -34,63 +34,44 @@
#include <google/protobuf/generated_message_util.h>
#include <atomic>
#include <limits>
#include <vector>
#include <google/protobuf/io/coded_stream_inl.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/metadata_lite.h>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format_lite.h>
// Must be included last
#include <google/protobuf/port_def.inc>
PROTOBUF_PRAGMA_INIT_SEG
#include <google/protobuf/wire_format_lite_inl.h>
namespace google {
namespace protobuf {
namespace internal {
void DestroyMessage(const void* message) {
static_cast<const MessageLite*>(message)->~MessageLite();
double Infinity() {
return std::numeric_limits<double>::infinity();
}
void DestroyString(const void* s) {
static_cast<const std::string*>(s)->~basic_string();
double NaN() {
return std::numeric_limits<double>::quiet_NaN();
}
PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT
PROTOBUF_ATTRIBUTE_INIT_PRIORITY ExplicitlyConstructed<std::string>
fixed_address_empty_string{}; // NOLINT
ExplicitlyConstructed< ::std::string> fixed_address_empty_string;
GOOGLE_PROTOBUF_DECLARE_ONCE(empty_string_once_init_);
void DeleteEmptyString() { fixed_address_empty_string.Destruct(); }
PROTOBUF_CONSTINIT std::atomic<bool> init_protobuf_defaults_state{false};
static bool InitProtobufDefaultsImpl() {
void InitEmptyString() {
fixed_address_empty_string.DefaultConstruct();
OnShutdownDestroyString(fixed_address_empty_string.get_mutable());
init_protobuf_defaults_state.store(true, std::memory_order_release);
return true;
OnShutdown(&DeleteEmptyString);
}
void InitProtobufDefaultsSlow() {
static bool is_inited = InitProtobufDefaultsImpl();
(void)is_inited;
}
// Force the initialization of the empty string.
// Normally, registration would do it, but we don't have any guarantee that
// there is any object with reflection.
PROTOBUF_ATTRIBUTE_INIT_PRIORITY static std::true_type init_empty_string =
(InitProtobufDefaultsSlow(), std::true_type{});
size_t StringSpaceUsedExcludingSelfLong(const std::string& str) {
size_t StringSpaceUsedExcludingSelfLong(const string& str) {
const void* start = &str;
const void* end = &str + 1;
if (start <= str.data() && str.data() < end) {
@@ -101,6 +82,12 @@ size_t StringSpaceUsedExcludingSelfLong(const std::string& str) {
}
}
void InitProtobufDefaults() {
GetEmptyString();
}
template <typename T>
const T& Get(const void* ptr) {
return *static_cast<const T*>(ptr);
@@ -116,96 +103,105 @@ struct PrimitiveTypeHelper;
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_BOOL> {
typedef bool Type;
static void Serialize(const void* ptr, io::CodedOutputStream* output) {
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteBoolNoTag(Get<bool>(ptr), output);
}
static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteBoolNoTagToArray(Get<Type>(ptr), buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_INT32> {
typedef int32_t Type;
static void Serialize(const void* ptr, io::CodedOutputStream* output) {
WireFormatLite::WriteInt32NoTag(Get<int32_t>(ptr), output);
typedef int32 Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteInt32NoTag(Get<int32>(ptr), output);
}
static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteInt32NoTagToArray(Get<Type>(ptr), buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_SINT32> {
typedef int32_t Type;
static void Serialize(const void* ptr, io::CodedOutputStream* output) {
WireFormatLite::WriteSInt32NoTag(Get<int32_t>(ptr), output);
typedef int32 Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteSInt32NoTag(Get<int32>(ptr), output);
}
static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteSInt32NoTagToArray(Get<Type>(ptr), buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_UINT32> {
typedef uint32_t Type;
static void Serialize(const void* ptr, io::CodedOutputStream* output) {
WireFormatLite::WriteUInt32NoTag(Get<uint32_t>(ptr), output);
typedef uint32 Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteUInt32NoTag(Get<uint32>(ptr), output);
}
static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteUInt32NoTagToArray(Get<Type>(ptr), buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_INT64> {
typedef int64_t Type;
static void Serialize(const void* ptr, io::CodedOutputStream* output) {
WireFormatLite::WriteInt64NoTag(Get<int64_t>(ptr), output);
typedef int64 Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteInt64NoTag(Get<int64>(ptr), output);
}
static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteInt64NoTagToArray(Get<Type>(ptr), buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_SINT64> {
typedef int64_t Type;
static void Serialize(const void* ptr, io::CodedOutputStream* output) {
WireFormatLite::WriteSInt64NoTag(Get<int64_t>(ptr), output);
typedef int64 Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteSInt64NoTag(Get<int64>(ptr), output);
}
static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteSInt64NoTagToArray(Get<Type>(ptr), buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_UINT64> {
typedef uint64_t Type;
static void Serialize(const void* ptr, io::CodedOutputStream* output) {
WireFormatLite::WriteUInt64NoTag(Get<uint64_t>(ptr), output);
typedef uint64 Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteUInt64NoTag(Get<uint64>(ptr), output);
}
static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteUInt64NoTagToArray(Get<Type>(ptr), buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
typedef uint32_t Type;
static void Serialize(const void* ptr, io::CodedOutputStream* output) {
WireFormatLite::WriteFixed32NoTag(Get<uint32_t>(ptr), output);
typedef uint32 Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteFixed32NoTag(Get<uint32>(ptr), output);
}
static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteFixed32NoTagToArray(Get<Type>(ptr), buffer);
}
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
typedef uint64_t Type;
static void Serialize(const void* ptr, io::CodedOutputStream* output) {
WireFormatLite::WriteFixed64NoTag(Get<uint64_t>(ptr), output);
typedef uint64 Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
WireFormatLite::WriteFixed64NoTag(Get<uint64>(ptr), output);
}
static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
return WireFormatLite::WriteFixed64NoTagToArray(Get<Type>(ptr), buffer);
}
};
@@ -217,12 +213,12 @@ struct PrimitiveTypeHelper<WireFormatLite::TYPE_ENUM>
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_SFIXED32>
: PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
typedef int32_t Type;
typedef int32 Type;
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_SFIXED64>
: PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
typedef int64_t Type;
typedef int64 Type;
};
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_FLOAT>
@@ -237,13 +233,14 @@ struct PrimitiveTypeHelper<WireFormatLite::TYPE_DOUBLE>
template <>
struct PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {
typedef std::string Type;
static void Serialize(const void* ptr, io::CodedOutputStream* output) {
typedef string Type;
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
const Type& value = *static_cast<const Type*>(ptr);
output->WriteVarint32(value.size());
output->WriteRawMaybeAliased(value.data(), value.size());
}
static uint8_t* SerializeToArray(const void* ptr, uint8_t* buffer) {
static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
const Type& value = *static_cast<const Type*>(ptr);
return io::CodedOutputStream::WriteStringWithSizeToArray(value, buffer);
}
@@ -254,10 +251,6 @@ struct PrimitiveTypeHelper<WireFormatLite::TYPE_BYTES>
: PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {};
template <>
struct PrimitiveTypeHelper<FieldMetadata::kInlinedType>
: PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {};
// We want to serialize to both CodedOutputStream and directly into byte arrays
// without duplicating the code. In fact we might want extra output channels in
// the future.
@@ -270,26 +263,27 @@ void SerializeTo(const void* ptr, O* output) {
}
template <typename O>
void WriteTagTo(uint32_t tag, O* output) {
void WriteTagTo(uint32 tag, O* output) {
SerializeTo<WireFormatLite::TYPE_UINT32>(&tag, output);
}
template <typename O>
void WriteLengthTo(uint32_t length, O* output) {
void WriteLengthTo(uint32 length, O* output) {
SerializeTo<WireFormatLite::TYPE_UINT32>(&length, output);
}
// Specialization for coded output stream
template <int type>
struct OutputHelper<io::CodedOutputStream, type> {
static void Serialize(const void* ptr, io::CodedOutputStream* output) {
struct OutputHelper< ::google::protobuf::io::CodedOutputStream, type> {
static void Serialize(const void* ptr,
::google::protobuf::io::CodedOutputStream* output) {
PrimitiveTypeHelper<type>::Serialize(ptr, output);
}
};
// Specialization for writing into a plain array
struct ArrayOutput {
uint8_t* ptr;
uint8* ptr;
bool is_deterministic;
};
@@ -301,32 +295,38 @@ struct OutputHelper<ArrayOutput, type> {
};
void SerializeMessageNoTable(const MessageLite* msg,
io::CodedOutputStream* output) {
::google::protobuf::io::CodedOutputStream* output) {
msg->SerializeWithCachedSizes(output);
}
void SerializeMessageNoTable(const MessageLite* msg, ArrayOutput* output) {
io::ArrayOutputStream array_stream(output->ptr, INT_MAX);
io::CodedOutputStream o(&array_stream);
o.SetSerializationDeterministic(output->is_deterministic);
msg->SerializeWithCachedSizes(&o);
output->ptr += o.ByteCount();
output->ptr = msg->InternalSerializeWithCachedSizesToArray(
output->is_deterministic, output->ptr);
}
// Helper to branch to fast path if possible
void SerializeMessageDispatch(const MessageLite& msg,
void SerializeMessageDispatch(const ::google::protobuf::MessageLite& msg,
const FieldMetadata* field_table, int num_fields,
int32_t /*cached_size*/,
io::CodedOutputStream* output) {
const uint8_t* base = reinterpret_cast<const uint8_t*>(&msg);
int32 cached_size,
::google::protobuf::io::CodedOutputStream* output) {
const uint8* base = reinterpret_cast<const uint8*>(&msg);
// Try the fast path
uint8* ptr = output->GetDirectBufferForNBytesAndAdvance(cached_size);
if (ptr) {
// We use virtual dispatch to enable dedicated generated code for the
// fast path.
msg.InternalSerializeWithCachedSizesToArray(
output->IsSerializationDeterministic(), ptr);
return;
}
SerializeInternal(base, field_table, num_fields, output);
}
// Helper to branch to fast path if possible
void SerializeMessageDispatch(const MessageLite& msg,
void SerializeMessageDispatch(const ::google::protobuf::MessageLite& msg,
const FieldMetadata* field_table, int num_fields,
int32_t /*cached_size*/, ArrayOutput* output) {
const uint8_t* base = reinterpret_cast<const uint8_t*>(&msg);
int32 cached_size, ArrayOutput* output) {
const uint8* base = reinterpret_cast<const uint8*>(&msg);
output->ptr = SerializeInternalToArray(base, field_table, num_fields,
output->is_deterministic, output->ptr);
}
@@ -345,9 +345,8 @@ void SerializeMessageTo(const MessageLite* msg, const void* table_ptr,
return;
}
const FieldMetadata* field_table = table->field_table;
const uint8_t* base = reinterpret_cast<const uint8_t*>(msg);
int cached_size =
*reinterpret_cast<const int32_t*>(base + field_table->offset);
const uint8* base = reinterpret_cast<const uint8*>(msg);
int cached_size = *reinterpret_cast<const int32*>(base + field_table->offset);
WriteLengthTo(cached_size, output);
int num_fields = table->num_fields - 1;
SerializeMessageDispatch(*msg, field_table + 1, num_fields, cached_size,
@@ -366,9 +365,8 @@ void SerializeGroupTo(const MessageLite* msg, const void* table_ptr,
return;
}
const FieldMetadata* field_table = table->field_table;
const uint8_t* base = reinterpret_cast<const uint8_t*>(msg);
int cached_size =
*reinterpret_cast<const int32_t*>(base + field_table->offset);
const uint8* base = reinterpret_cast<const uint8*>(msg);
int cached_size = *reinterpret_cast<const int32*>(base + field_table->offset);
int num_fields = table->num_fields - 1;
SerializeMessageDispatch(*msg, field_table + 1, num_fields, cached_size,
output);
@@ -418,15 +416,6 @@ struct SingularFieldHelper<WireFormatLite::TYPE_MESSAGE> {
}
};
template <>
struct SingularFieldHelper<FieldMetadata::kInlinedType> {
template <typename O>
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
WriteTagTo(md.tag, output);
SerializeTo<FieldMetadata::kInlinedType>(&Get<std::string>(field), output);
}
};
template <int type>
struct RepeatedFieldHelper {
template <typename O>
@@ -492,17 +481,13 @@ struct RepeatedFieldHelper<WireFormatLite::TYPE_MESSAGE> {
for (int i = 0; i < AccessorHelper::Size(array); i++) {
WriteTagTo(md.tag, output);
SerializeMessageTo(
static_cast<const MessageLite*>(AccessorHelper::Get(array, i)),
md.ptr, output);
static_cast<const MessageLite*>(AccessorHelper::Get(array, i)), md.ptr,
output);
}
}
};
template <>
struct RepeatedFieldHelper<FieldMetadata::kInlinedType>
: RepeatedFieldHelper<WireFormatLite::TYPE_STRING> {};
template <int type>
struct PackedFieldHelper {
template <typename O>
@@ -512,7 +497,7 @@ struct PackedFieldHelper {
if (array.empty()) return;
WriteTagTo(md.tag, output);
int cached_size =
Get<int>(static_cast<const uint8_t*>(field) + sizeof(RepeatedField<T>));
Get<int>(static_cast<const uint8*>(field) + sizeof(RepeatedField<T>));
WriteLengthTo(cached_size, output);
for (int i = 0; i < array.size(); i++) {
SerializeTo<type>(&array[i], output);
@@ -523,8 +508,7 @@ struct PackedFieldHelper {
template <>
struct PackedFieldHelper<WireFormatLite::TYPE_STRING> {
template <typename O>
static void Serialize(const void* /*field*/, const FieldMetadata& md,
O* /*output*/) {
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
GOOGLE_LOG(FATAL) << "Not implemented field number " << md.tag << " with type "
<< md.type;
}
@@ -539,9 +523,6 @@ struct PackedFieldHelper<WireFormatLite::TYPE_GROUP>
template <>
struct PackedFieldHelper<WireFormatLite::TYPE_MESSAGE>
: PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
template <>
struct PackedFieldHelper<FieldMetadata::kInlinedType>
: PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
template <int type>
struct OneOfFieldHelper {
@@ -552,15 +533,6 @@ struct OneOfFieldHelper {
};
template <>
struct OneOfFieldHelper<FieldMetadata::kInlinedType> {
template <typename O>
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
SingularFieldHelper<FieldMetadata::kInlinedType>::Serialize(
Get<const std::string*>(field), md, output);
}
};
void SerializeNotImplemented(int field) {
GOOGLE_LOG(FATAL) << "Not implemented field number " << field;
}
@@ -592,20 +564,15 @@ bool IsNull<WireFormatLite::TYPE_BYTES>(const void* ptr) {
template <>
bool IsNull<WireFormatLite::TYPE_GROUP>(const void* ptr) {
return Get<const MessageLite*>(ptr) == nullptr;
return Get<const MessageLite*>(ptr) == NULL;
}
template <>
bool IsNull<WireFormatLite::TYPE_MESSAGE>(const void* ptr) {
return Get<const MessageLite*>(ptr) == nullptr;
return Get<const MessageLite*>(ptr) == NULL;
}
template <>
bool IsNull<FieldMetadata::kInlinedType>(const void* ptr) {
return static_cast<const std::string*>(ptr)->empty();
}
#define SERIALIZERS_FOR_TYPE(type) \
case SERIALIZE_TABLE_OP(type, FieldMetadata::kPresence): \
if (!IsPresent(base, field_metadata.has_offset)) continue; \
@@ -627,13 +594,13 @@ bool IsNull<FieldMetadata::kInlinedType>(const void* ptr) {
OneOfFieldHelper<type>::Serialize(ptr, field_metadata, output); \
break
void SerializeInternal(const uint8_t* base,
void SerializeInternal(const uint8* base,
const FieldMetadata* field_metadata_table,
int32_t num_fields, io::CodedOutputStream* output) {
SpecialSerializer func = nullptr;
int32 num_fields,
::google::protobuf::io::CodedOutputStream* output) {
for (int i = 0; i < num_fields; i++) {
const FieldMetadata& field_metadata = field_metadata_table[i];
const uint8_t* ptr = base + field_metadata.offset;
const uint8* ptr = base + field_metadata.offset;
switch (field_metadata.type) {
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_DOUBLE);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FLOAT);
@@ -653,14 +620,13 @@ void SerializeInternal(const uint8_t* base,
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64);
SERIALIZERS_FOR_TYPE(FieldMetadata::kInlinedType);
// Special cases
case FieldMetadata::kSpecial:
func = reinterpret_cast<SpecialSerializer>(
const_cast<void*>(field_metadata.ptr));
func(base, field_metadata.offset, field_metadata.tag,
field_metadata.has_offset, output);
reinterpret_cast<SpecialSerializer>(
const_cast<void*>(field_metadata.ptr))(
base, field_metadata.offset, field_metadata.tag,
field_metadata.has_offset, output);
break;
default:
// __builtin_unreachable()
@@ -669,16 +635,15 @@ void SerializeInternal(const uint8_t* base,
}
}
uint8_t* SerializeInternalToArray(const uint8_t* base,
const FieldMetadata* field_metadata_table,
int32_t num_fields, bool is_deterministic,
uint8_t* buffer) {
uint8* SerializeInternalToArray(const uint8* base,
const FieldMetadata* field_metadata_table,
int32 num_fields, bool is_deterministic,
uint8* buffer) {
ArrayOutput array_output = {buffer, is_deterministic};
ArrayOutput* output = &array_output;
SpecialSerializer func = nullptr;
for (int i = 0; i < num_fields; i++) {
const FieldMetadata& field_metadata = field_metadata_table[i];
const uint8_t* ptr = base + field_metadata.offset;
const uint8* ptr = base + field_metadata.offset;
switch (field_metadata.type) {
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_DOUBLE);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FLOAT);
@@ -698,17 +663,16 @@ uint8_t* SerializeInternalToArray(const uint8_t* base,
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64);
SERIALIZERS_FOR_TYPE(FieldMetadata::kInlinedType);
// Special cases
case FieldMetadata::kSpecial: {
io::ArrayOutputStream array_stream(array_output.ptr, INT_MAX);
io::CodedOutputStream output_stream(&array_stream);
output_stream.SetSerializationDeterministic(is_deterministic);
func = reinterpret_cast<SpecialSerializer>(
const_cast<void*>(field_metadata.ptr));
func(base, field_metadata.offset, field_metadata.tag,
field_metadata.has_offset, &output_stream);
array_output.ptr += output_stream.ByteCount();
io::CodedOutputStream output(&array_stream);
output.SetSerializationDeterministic(is_deterministic);
reinterpret_cast<SpecialSerializer>(
const_cast<void*>(field_metadata.ptr))(
base, field_metadata.offset, field_metadata.tag,
field_metadata.has_offset, &output);
array_output.ptr += output.ByteCount();
} break;
default:
// __builtin_unreachable()
@@ -719,50 +683,39 @@ uint8_t* SerializeInternalToArray(const uint8_t* base,
}
#undef SERIALIZERS_FOR_TYPE
void ExtensionSerializer(const MessageLite* extendee, const uint8_t* ptr,
uint32_t offset, uint32_t tag, uint32_t has_offset,
io::CodedOutputStream* output) {
void ExtensionSerializer(const uint8* ptr, uint32 offset, uint32 tag,
uint32 has_offset,
::google::protobuf::io::CodedOutputStream* output) {
reinterpret_cast<const ExtensionSet*>(ptr + offset)
->SerializeWithCachedSizes(extendee, tag, has_offset, output);
->SerializeWithCachedSizes(tag, has_offset, output);
}
void UnknownFieldSerializerLite(const uint8_t* ptr, uint32_t offset,
uint32_t /*tag*/, uint32_t /*has_offset*/,
io::CodedOutputStream* output) {
void UnknownFieldSerializerLite(const uint8* ptr, uint32 offset, uint32 tag,
uint32 has_offset,
::google::protobuf::io::CodedOutputStream* output) {
output->WriteString(
reinterpret_cast<const InternalMetadata*>(ptr + offset)
->unknown_fields<std::string>(&internal::GetEmptyString));
reinterpret_cast<const InternalMetadataWithArenaLite*>(ptr + offset)
->unknown_fields());
}
MessageLite* DuplicateIfNonNullInternal(MessageLite* message) {
MessageLite* DuplicateIfNonNullInternal(MessageLite* message, Arena* arena) {
if (message) {
MessageLite* ret = message->New();
MessageLite* ret = message->New(arena);
ret->CheckTypeAndMergeFrom(*message);
return ret;
} else {
return nullptr;
return NULL;
}
}
void GenericSwap(MessageLite* m1, MessageLite* m2) {
std::unique_ptr<MessageLite> tmp(m1->New());
tmp->CheckTypeAndMergeFrom(*m1);
m1->Clear();
m1->CheckTypeAndMergeFrom(*m2);
m2->Clear();
m2->CheckTypeAndMergeFrom(*tmp);
}
// Returns a message owned by this Arena. This may require Own()ing or
// duplicating the message.
MessageLite* GetOwnedMessageInternal(Arena* message_arena,
MessageLite* submessage,
Arena* submessage_arena) {
GOOGLE_DCHECK(Arena::InternalHelper<MessageLite>::GetOwningArena(submessage) ==
submessage_arena);
GOOGLE_DCHECK(submessage->GetArena() == submessage_arena);
GOOGLE_DCHECK(message_arena != submessage_arena);
GOOGLE_DCHECK_EQ(submessage_arena, nullptr);
if (message_arena != nullptr && submessage_arena == nullptr) {
if (message_arena != NULL && submessage_arena == NULL) {
message_arena->Own(submessage);
return submessage;
} else {
@@ -775,5 +728,3 @@ MessageLite* GetOwnedMessageInternal(Arena* message_arena,
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
+218 -111
View File
@@ -39,69 +39,73 @@
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
#include <assert.h>
#include <atomic>
#include <climits>
#include <string>
#include <vector>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/any.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/has_bits.h>
#include <google/protobuf/implicit_weak_message.h>
#include <google/protobuf/map_entry_lite.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/stubs/once.h> // Add direct dep on port for pb.cc
#include <google/protobuf/port.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/port_def.inc>
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
namespace google {
namespace protobuf {
class Arena;
class Message;
namespace io {
class CodedInputStream;
}
namespace io { class CodedInputStream; }
namespace internal {
template <typename To, typename From>
inline To DownCast(From* f) {
return PROTOBUF_NAMESPACE_ID::internal::down_cast<To>(f);
}
template <typename To, typename From>
inline To DownCast(From& f) {
return PROTOBUF_NAMESPACE_ID::internal::down_cast<To>(f);
}
// Annotation for the compiler to emit a deprecation message if a field marked
// with option 'deprecated=true' is used in the code, or for other things in
// generated code which are deprecated.
//
// For internal use in the pb.cc files, deprecation warnings are suppressed
// there.
#undef DEPRECATED_PROTOBUF_FIELD
#define PROTOBUF_DEPRECATED
#define GOOGLE_PROTOBUF_DEPRECATED_ATTR
// This fastpath inlines a single branch instead of having to make the
// InitProtobufDefaults function call.
// It also generates less inlined code than a function-scope static initializer.
PROTOBUF_EXPORT extern std::atomic<bool> init_protobuf_defaults_state;
PROTOBUF_EXPORT void InitProtobufDefaultsSlow();
PROTOBUF_EXPORT inline void InitProtobufDefaults() {
if (PROTOBUF_PREDICT_FALSE(
!init_protobuf_defaults_state.load(std::memory_order_acquire))) {
InitProtobufDefaultsSlow();
}
}
// Returns the offset of the given field within the given aggregate type.
// This is equivalent to the ANSI C offsetof() macro. However, according
// to the C++ standard, offsetof() only works on POD types, and GCC
// enforces this requirement with a warning. In practice, this rule is
// unnecessarily strict; there is probably no compiler or platform on
// which the offsets of the direct fields of a class are non-constant.
// Fields inherited from superclasses *can* have non-constant offsets,
// but that's not what this macro will be used for.
#if defined(__clang__)
// For Clang we use __builtin_offsetof() and suppress the warning,
// to avoid Control Flow Integrity and UBSan vptr sanitizers from
// crashing while trying to validate the invalid reinterpet_casts.
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TYPE, FIELD) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
__builtin_offsetof(TYPE, FIELD) \
_Pragma("clang diagnostic pop")
#else
// Note that we calculate relative to the pointer value 16 here since if we
// just use zero, GCC complains about dereferencing a NULL pointer. We
// choose 16 rather than some other number just in case the compiler would
// be confused by an unaligned pointer.
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TYPE, FIELD) \
static_cast< ::google::protobuf::uint32>( \
reinterpret_cast<const char*>( \
&reinterpret_cast<const TYPE*>(16)->FIELD) - \
reinterpret_cast<const char*>(16))
#endif
// This used by proto1
PROTOBUF_EXPORT inline const std::string& GetEmptyString() {
InitProtobufDefaults();
return GetEmptyStringAlreadyInited();
}
// Constants for special floating point values.
LIBPROTOBUF_EXPORT double Infinity();
LIBPROTOBUF_EXPORT double NaN();
// True if IsInitialized() is true for all elements of t. Type is expected
@@ -109,67 +113,178 @@ PROTOBUF_EXPORT inline const std::string& GetEmptyString() {
// helper here to keep the protobuf compiler from ever having to emit loops in
// IsInitialized() methods. We want the C++ compiler to inline this or not
// as it sees fit.
template <typename Msg>
bool AllAreInitialized(const RepeatedPtrField<Msg>& t) {
for (int i = t.size(); --i >= 0;) {
template <class Type> bool AllAreInitialized(const Type& t) {
for (int i = t.size(); --i >= 0; ) {
if (!t.Get(i).IsInitialized()) return false;
}
return true;
}
// "Weak" variant of AllAreInitialized, used to implement implicit weak fields.
// This version operates on MessageLite to avoid introducing a dependency on the
// concrete message type.
template <class T>
bool AllAreInitializedWeak(const RepeatedPtrField<T>& t) {
for (int i = t.size(); --i >= 0;) {
if (!reinterpret_cast<const RepeatedPtrFieldBase&>(t)
.Get<ImplicitWeakTypeHandler<T> >(i)
.IsInitialized()) {
return false;
}
}
return true;
LIBPROTOBUF_EXPORT void InitProtobufDefaults();
struct LIBPROTOBUF_EXPORT FieldMetadata {
uint32 offset; // offset of this field in the struct
uint32 tag; // field * 8 + wire_type
// byte offset * 8 + bit_offset;
// if the high bit is set then this is the byte offset of the oneof_case
// for this field.
uint32 has_offset;
uint32 type; // the type of this field.
const void* ptr; // auxiliary data
// From the serializer point of view each fundamental type can occur in
// 4 different ways. For simplicity we treat all combinations as a cartesion
// product although not all combinations are allowed.
enum FieldTypeClass {
kPresence,
kNoPresence,
kRepeated,
kPacked,
kOneOf,
kNumTypeClasses // must be last enum
};
// C++ protobuf has 20 fundamental types, were we added Cord and StringPiece
// and also distinquish the same types if they have different wire format.
enum {
kCordType = 19,
kStringPieceType = 20,
kNumTypes = 20,
kSpecial = kNumTypes * kNumTypeClasses,
};
static int CalculateType(int fundamental_type, FieldTypeClass type_class);
};
inline bool IsPresent(const void* base, uint32 hasbit) {
const uint32* has_bits_array = static_cast<const uint32*>(base);
return has_bits_array[hasbit / 32] & (1u << (hasbit & 31));
}
inline bool IsPresent(const void* base, uint32_t hasbit) {
const uint32_t* has_bits_array = static_cast<const uint32_t*>(base);
return (has_bits_array[hasbit / 32] & (1u << (hasbit & 31))) != 0;
}
inline bool IsOneofPresent(const void* base, uint32_t offset, uint32_t tag) {
const uint32_t* oneof = reinterpret_cast<const uint32_t*>(
static_cast<const uint8_t*>(base) + offset);
inline bool IsOneofPresent(const void* base, uint32 offset, uint32 tag) {
const uint32* oneof =
reinterpret_cast<const uint32*>(static_cast<const uint8*>(base) + offset);
return *oneof == tag >> 3;
}
typedef void (*SpecialSerializer)(const uint8_t* base, uint32_t offset,
uint32_t tag, uint32_t has_offset,
io::CodedOutputStream* output);
typedef void (*SpecialSerializer)(const uint8* base, uint32 offset, uint32 tag,
uint32 has_offset,
::google::protobuf::io::CodedOutputStream* output);
PROTOBUF_EXPORT void ExtensionSerializer(const MessageLite* extendee,
const uint8_t* ptr, uint32_t offset,
uint32_t tag, uint32_t has_offset,
io::CodedOutputStream* output);
PROTOBUF_EXPORT void UnknownFieldSerializerLite(const uint8_t* base,
uint32_t offset, uint32_t tag,
uint32_t has_offset,
io::CodedOutputStream* output);
LIBPROTOBUF_EXPORT void ExtensionSerializer(const uint8* base, uint32 offset, uint32 tag,
uint32 has_offset,
::google::protobuf::io::CodedOutputStream* output);
LIBPROTOBUF_EXPORT void UnknownFieldSerializerLite(const uint8* base, uint32 offset, uint32 tag,
uint32 has_offset,
::google::protobuf::io::CodedOutputStream* output);
PROTOBUF_EXPORT MessageLite* DuplicateIfNonNullInternal(MessageLite* message);
PROTOBUF_EXPORT MessageLite* GetOwnedMessageInternal(Arena* message_arena,
MessageLite* submessage,
Arena* submessage_arena);
PROTOBUF_EXPORT void GenericSwap(MessageLite* m1, MessageLite* m2);
// We specialize GenericSwap for non-lite messages to benefit from reflection.
PROTOBUF_EXPORT void GenericSwap(Message* m1, Message* m2);
struct SerializationTable {
int num_fields;
const FieldMetadata* field_table;
};
LIBPROTOBUF_EXPORT void SerializeInternal(const uint8* base, const FieldMetadata* table,
int num_fields, ::google::protobuf::io::CodedOutputStream* output);
inline void TableSerialize(const ::google::protobuf::MessageLite& msg,
const SerializationTable* table,
::google::protobuf::io::CodedOutputStream* output) {
const FieldMetadata* field_table = table->field_table;
int num_fields = table->num_fields - 1;
const uint8* base = reinterpret_cast<const uint8*>(&msg);
// TODO(gerbens) This skips the first test if we could use the fast
// array serialization path, we should make this
// int cached_size =
// *reinterpret_cast<const int32*>(base + field_table->offset);
// SerializeWithCachedSize(msg, field_table + 1, num_fields, cached_size, ...)
// But we keep conformance with the old way for now.
SerializeInternal(base, field_table + 1, num_fields, output);
}
uint8* SerializeInternalToArray(const uint8* base, const FieldMetadata* table,
int num_fields, bool is_deterministic,
uint8* buffer);
inline uint8* TableSerializeToArray(const ::google::protobuf::MessageLite& msg,
const SerializationTable* table,
bool is_deterministic, uint8* buffer) {
const uint8* base = reinterpret_cast<const uint8*>(&msg);
const FieldMetadata* field_table = table->field_table + 1;
int num_fields = table->num_fields - 1;
return SerializeInternalToArray(base, field_table, num_fields,
is_deterministic, buffer);
}
template <typename T>
T* DuplicateIfNonNull(T* message) {
struct CompareHelper {
bool operator()(const T& a, const T& b) { return a < b; }
};
template <>
struct CompareHelper<ArenaStringPtr> {
bool operator()(const ArenaStringPtr& a, const ArenaStringPtr& b) {
return a.Get() < b.Get();
}
};
struct CompareMapKey {
template <typename T>
bool operator()(const MapEntryHelper<T>& a, const MapEntryHelper<T>& b) {
return Compare(a.key_, b.key_);
}
template <typename T>
bool Compare(const T& a, const T& b) {
return CompareHelper<T>()(a, b);
}
};
template <typename MapFieldType, const SerializationTable* table>
void MapFieldSerializer(const uint8* base, uint32 offset, uint32 tag,
uint32 has_offset,
::google::protobuf::io::CodedOutputStream* output) {
typedef MapEntryHelper<typename MapFieldType::EntryTypeTrait> Entry;
typedef typename MapFieldType::MapType::const_iterator Iter;
const MapFieldType& map_field =
*reinterpret_cast<const MapFieldType*>(base + offset);
const SerializationTable* t =
table +
has_offset; // has_offset is overloaded for maps to mean table offset
if (!output->IsSerializationDeterministic()) {
for (Iter it = map_field.GetMap().begin(); it != map_field.GetMap().end();
++it) {
Entry map_entry(*it);
output->WriteVarint32(tag);
output->WriteVarint32(map_entry._cached_size_);
SerializeInternal(reinterpret_cast<const uint8*>(&map_entry),
t->field_table, t->num_fields, output);
}
} else {
std::vector<Entry> v;
for (Iter it = map_field.GetMap().begin(); it != map_field.GetMap().end();
++it) {
v.push_back(Entry(*it));
}
std::sort(v.begin(), v.end(), CompareMapKey());
for (int i = 0; i < v.size(); i++) {
output->WriteVarint32(tag);
output->WriteVarint32(v[i]._cached_size_);
SerializeInternal(reinterpret_cast<const uint8*>(&v[i]), t->field_table,
t->num_fields, output);
}
}
}
LIBPROTOBUF_EXPORT MessageLite* DuplicateIfNonNullInternal(MessageLite* message, Arena* arena);
LIBPROTOBUF_EXPORT MessageLite* GetOwnedMessageInternal(Arena* message_arena,
MessageLite* submessage,
Arena* submessage_arena);
template <typename T>
T* DuplicateIfNonNull(T* message, Arena* arena) {
// The casts must be reinterpret_cast<> because T might be a forward-declared
// type that the compiler doesn't know is related to MessageLite.
return reinterpret_cast<T*>(
DuplicateIfNonNullInternal(reinterpret_cast<MessageLite*>(message)));
return reinterpret_cast<T*>(DuplicateIfNonNullInternal(
reinterpret_cast<MessageLite*>(message), arena));
}
template <typename T>
@@ -182,32 +297,24 @@ T* GetOwnedMessage(Arena* message_arena, T* submessage,
submessage_arena));
}
// Hide atomic from the public header and allow easy change to regular int
// on platforms where the atomic might have a perf impact.
class PROTOBUF_EXPORT CachedSize {
public:
int Get() const { return size_.load(std::memory_order_relaxed); }
void Set(int size) { size_.store(size, std::memory_order_relaxed); }
private:
std::atomic<int> size_{0};
};
PROTOBUF_EXPORT void DestroyMessage(const void* message);
PROTOBUF_EXPORT void DestroyString(const void* s);
// Destroy (not delete) the message
inline void OnShutdownDestroyMessage(const void* ptr) {
OnShutdownRun(DestroyMessage, ptr);
}
// Destroy the string (call std::string destructor)
inline void OnShutdownDestroyString(const std::string* ptr) {
OnShutdownRun(DestroyString, ptr);
// Returns a message owned by this Arena. This may require Own()ing or
// duplicating the message.
template <typename T>
T* GetOwnedMessage(T* message, Arena* arena) {
GOOGLE_DCHECK(message);
Arena* message_arena = google::protobuf::Arena::GetArena(message);
if (message_arena == arena) {
return message;
} else if (arena != NULL && message_arena == NULL) {
arena->Own(message);
return message;
} else {
return DuplicateIfNonNull(message, arena);
}
}
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
+9 -20
View File
@@ -32,32 +32,27 @@
#define GOOGLE_PROTOBUF_HAS_BITS_H__
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/port.h>
#include <google/protobuf/port_def.inc>
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
#include <google/protobuf/stubs/port.h>
namespace google {
namespace protobuf {
namespace internal {
template <size_t doublewords>
template<size_t doublewords>
class HasBits {
public:
PROTOBUF_NDEBUG_INLINE constexpr HasBits() : has_bits_{} {}
HasBits() GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE { Clear(); }
PROTOBUF_NDEBUG_INLINE void Clear() {
void Clear() GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE {
memset(has_bits_, 0, sizeof(has_bits_));
}
PROTOBUF_NDEBUG_INLINE uint32_t& operator[](int index) {
::google::protobuf::uint32& operator[](int index) GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE {
return has_bits_[index];
}
PROTOBUF_NDEBUG_INLINE const uint32_t& operator[](int index) const {
const ::google::protobuf::uint32& operator[](int index) const
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE {
return has_bits_[index];
}
@@ -69,14 +64,10 @@ class HasBits {
return !(*this == rhs);
}
void Or(const HasBits<doublewords>& rhs) {
for (size_t i = 0; i < doublewords; i++) has_bits_[i] |= rhs[i];
}
bool empty() const;
private:
uint32_t has_bits_[doublewords];
::google::protobuf::uint32 has_bits_[doublewords];
};
template <>
@@ -109,8 +100,6 @@ inline bool HasBits<doublewords>::empty() const {
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_HAS_BITS_H__
@@ -1,186 +0,0 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_PROTOBUF_IMPLICIT_WEAK_MESSAGE_H__
#define GOOGLE_PROTOBUF_IMPLICIT_WEAK_MESSAGE_H__
#include <string>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/repeated_field.h>
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
#include <google/protobuf/port_def.inc>
// This file is logically internal-only and should only be used by protobuf
// generated code.
namespace google {
namespace protobuf {
namespace internal {
// An implementation of MessageLite that treats all data as unknown. This type
// acts as a placeholder for an implicit weak field in the case where the true
// message type does not get linked into the binary.
class PROTOBUF_EXPORT ImplicitWeakMessage : public MessageLite {
public:
ImplicitWeakMessage() {}
explicit ImplicitWeakMessage(Arena* arena) : MessageLite(arena) {}
static const ImplicitWeakMessage* default_instance();
std::string GetTypeName() const override { return ""; }
MessageLite* New(Arena* arena) const override {
return Arena::CreateMessage<ImplicitWeakMessage>(arena);
}
void Clear() override { data_.clear(); }
bool IsInitialized() const override { return true; }
void CheckTypeAndMergeFrom(const MessageLite& other) override {
data_.append(static_cast<const ImplicitWeakMessage&>(other).data_);
}
const char* _InternalParse(const char* ptr, ParseContext* ctx) final;
size_t ByteSizeLong() const override { return data_.size(); }
uint8_t* _InternalSerialize(uint8_t* target,
io::EpsCopyOutputStream* stream) const final {
return stream->WriteRaw(data_.data(), static_cast<int>(data_.size()),
target);
}
int GetCachedSize() const override { return static_cast<int>(data_.size()); }
typedef void InternalArenaConstructable_;
private:
std::string data_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImplicitWeakMessage);
};
// A type handler for use with implicit weak repeated message fields.
template <typename ImplicitWeakType>
class ImplicitWeakTypeHandler {
public:
typedef MessageLite Type;
static constexpr bool Moveable = false;
static inline MessageLite* NewFromPrototype(const MessageLite* prototype,
Arena* arena = nullptr) {
return prototype->New(arena);
}
static inline void Delete(MessageLite* value, Arena* arena) {
if (arena == nullptr) {
delete value;
}
}
static inline Arena* GetArena(MessageLite* value) {
return value->GetArena();
}
static inline void Clear(MessageLite* value) { value->Clear(); }
static void Merge(const MessageLite& from, MessageLite* to) {
to->CheckTypeAndMergeFrom(from);
}
};
} // namespace internal
template <typename T>
struct WeakRepeatedPtrField {
using TypeHandler = internal::ImplicitWeakTypeHandler<T>;
constexpr WeakRepeatedPtrField() : weak() {}
explicit WeakRepeatedPtrField(Arena* arena) : weak(arena) {}
~WeakRepeatedPtrField() { weak.template Destroy<TypeHandler>(); }
typedef internal::RepeatedPtrIterator<MessageLite> iterator;
typedef internal::RepeatedPtrIterator<const MessageLite> const_iterator;
typedef internal::RepeatedPtrOverPtrsIterator<MessageLite*, void*>
pointer_iterator;
typedef internal::RepeatedPtrOverPtrsIterator<const MessageLite* const,
const void* const>
const_pointer_iterator;
iterator begin() { return iterator(base().raw_data()); }
const_iterator begin() const { return iterator(base().raw_data()); }
const_iterator cbegin() const { return begin(); }
iterator end() { return begin() + base().size(); }
const_iterator end() const { return begin() + base().size(); }
const_iterator cend() const { return end(); }
pointer_iterator pointer_begin() {
return pointer_iterator(base().raw_mutable_data());
}
const_pointer_iterator pointer_begin() const {
return const_pointer_iterator(base().raw_mutable_data());
}
pointer_iterator pointer_end() {
return pointer_iterator(base().raw_mutable_data() + base().size());
}
const_pointer_iterator pointer_end() const {
return const_pointer_iterator(base().raw_mutable_data() + base().size());
}
MessageLite* AddWeak(const MessageLite* prototype) {
return base().AddWeak(prototype);
}
T* Add() { return weak.Add(); }
void Clear() { base().template Clear<TypeHandler>(); }
void MergeFrom(const WeakRepeatedPtrField& other) {
base().template MergeFrom<TypeHandler>(other.base());
}
void InternalSwap(WeakRepeatedPtrField* other) {
base().InternalSwap(&other->base());
}
const internal::RepeatedPtrFieldBase& base() const { return weak; }
internal::RepeatedPtrFieldBase& base() { return weak; }
// Union disables running the destructor. Which would create a strong link.
// Instead we explicitly destroy the underlying base through the virtual
// destructor.
union {
RepeatedPtrField<T> weak;
};
};
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_IMPLICIT_WEAK_MESSAGE_H__
@@ -1,384 +0,0 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__
#define GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__
#include <string>
#include <utility>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/port.h>
#include <google/protobuf/stubs/strutil.h>
// Must be included last.
#include <google/protobuf/port_def.inc>
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
namespace google {
namespace protobuf {
class Arena;
namespace internal {
// InlinedStringField wraps a std::string instance and exposes an API similar to
// ArenaStringPtr's wrapping of a std::string* instance.
//
// default_value parameters are taken for consistency with ArenaStringPtr, but
// are not used for most methods. With inlining, these should be removed from
// the generated binary.
//
// InlinedStringField has a donating mechanism that allows string buffer
// allocated on arena. A string is donated means both the string container and
// the data buffer are on arena. The donating mechanism here is similar to the
// one in ArenaStringPtr with some differences:
//
// When an InlinedStringField is constructed, the donating state is true. This
// is because the string container is directly stored in the message on the
// arena:
//
// Construction: donated=true
// Arena:
// +-----------------------+
// |Message foo: |
// | +-------------------+ |
// | |InlinedStringField:| |
// | | +-----+ | |
// | | | | | | | |
// | | +-----+ | |
// | +-------------------+ |
// +-----------------------+
//
// When lvalue Set is called, the donating state is still true. String data will
// be allocated on the arena:
//
// Lvalue Set: donated=true
// Arena:
// +-----------------------+
// |Message foo: |
// | +-------------------+ |
// | |InlinedStringField:| |
// | | +-----+ | |
// | | | | | | | |
// | | +|----+ | |
// | +--|----------------+ |
// | V |
// | +----------------+ |
// | |'f','o','o',... | |
// | +----------------+ |
// +-----------------------+
//
// Some operations will undonate a donated string, including: Mutable,
// SetAllocated, Rvalue Set, and Swap with a non-donated string.
//
// For more details of the donating states transitions, go/pd-inlined-string.
class PROTOBUF_EXPORT InlinedStringField {
public:
InlinedStringField() { Init(); }
inline void Init() { new (get_mutable()) std::string(); }
// Add the dummy parameter just to make InlinedStringField(nullptr)
// unambiguous.
constexpr InlinedStringField(
const ExplicitlyConstructed<std::string>* /*default_value*/,
bool /*dummy*/)
: value_{} {}
explicit InlinedStringField(const std::string& default_value);
explicit InlinedStringField(Arena* arena);
~InlinedStringField() { Destruct(); }
// Lvalue Set. To save space, we pack the donating states of multiple
// InlinedStringFields into an uint32_t `donating_states`. The `mask`
// indicates the position of the bit for this InlinedStringField. `donated` is
// whether this field is donated.
//
// The caller should guarantee that:
//
// `donated == ((donating_states & ~mask) != 0)`
//
// This method never changes the `donating_states`.
void Set(const std::string* default_value, ConstStringParam value,
Arena* arena, bool donated, uint32_t* /*donating_states*/,
uint32_t /*mask*/) {
(void)arena;
(void)donated;
SetNoArena(default_value, value);
}
// Rvalue Set. If this field is donated, this method will undonate this field
// by mutating the `donating_states` according to `mask`.
void Set(const std::string* default_value, std::string&& value, Arena* arena,
bool donated, uint32_t* donating_states, uint32_t mask);
template <typename FirstParam>
void Set(FirstParam p1, const char* str, ::google::protobuf::Arena* arena, bool donated,
uint32_t* donating_states, uint32_t mask) {
Set(p1, ConstStringParam(str), arena, donated, donating_states, mask);
}
template <typename FirstParam>
void Set(FirstParam p1, const char* str, size_t size, ::google::protobuf::Arena* arena,
bool donated, uint32_t* donating_states, uint32_t mask) {
ConstStringParam sp{str, size}; // for string_view and `const string &`
Set(p1, sp, arena, donated, donating_states, mask);
}
template <typename FirstParam, typename RefWrappedType>
void Set(FirstParam p1,
std::reference_wrapper<RefWrappedType> const_string_ref,
::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
uint32_t mask) {
Set(p1, const_string_ref.get(), arena, donated, donating_states, mask);
}
template <typename FirstParam, typename SecondParam>
void SetBytes(FirstParam p1, SecondParam&& p2, ::google::protobuf::Arena* arena,
bool donated, uint32_t* donating_states, uint32_t mask) {
Set(p1, static_cast<SecondParam&&>(p2), arena, donated, donating_states,
mask);
}
template <typename FirstParam>
void SetBytes(FirstParam p1, const void* str, size_t size,
::google::protobuf::Arena* arena, bool donated, uint32_t* donating_states,
uint32_t mask) {
// Must work whether ConstStringParam is string_view or `const string &`
ConstStringParam sp{static_cast<const char*>(str), size};
Set(p1, sp, arena, donated, donating_states, mask);
}
PROTOBUF_NDEBUG_INLINE void SetNoArena(const std::string* default_value,
StringPiece value);
PROTOBUF_NDEBUG_INLINE void SetNoArena(const std::string* default_value,
std::string&& value);
// Basic accessors.
PROTOBUF_NDEBUG_INLINE const std::string& Get() const { return GetNoArena(); }
PROTOBUF_NDEBUG_INLINE const std::string& GetNoArena() const;
// Mutable returns a std::string* instance that is heap-allocated. If this
// field is donated, this method undonates this field by mutating the
// `donating_states` according to `mask`, and copies the content of the
// original string to the returning string.
std::string* Mutable(const LazyString& default_value, Arena* arena,
bool donated, uint32_t* donating_states, uint32_t mask);
std::string* Mutable(ArenaStringPtr::EmptyDefault, Arena* arena, bool donated,
uint32_t* donating_states, uint32_t mask);
// Release returns a std::string* instance that is heap-allocated and is not
// Own()'d by any arena. If the field is not set, this returns nullptr. The
// caller retains ownership. Clears this field back to nullptr state. Used to
// implement release_<field>() methods on generated classes.
PROTOBUF_NODISCARD std::string* Release(const std::string* default_value,
Arena* arena, bool donated);
PROTOBUF_NODISCARD std::string* ReleaseNonDefault(
const std::string* default_value, Arena* arena);
std::string* ReleaseNonDefaultNoArena(const std::string* default_value);
// Takes a std::string that is heap-allocated, and takes ownership. The
// std::string's destructor is registered with the arena. Used to implement
// set_allocated_<field> in generated classes.
//
// If this field is donated, this method undonates this field by mutating the
// `donating_states` according to `mask`.
void SetAllocated(const std::string* default_value, std::string* value,
Arena* arena, bool donated, uint32_t* donating_states,
uint32_t mask);
void SetAllocatedNoArena(const std::string* default_value,
std::string* value);
// When one of `this` and `from` is donated and the other is not donated, this
// method will undonate the donated one and swap the two heap-allocated
// strings.
PROTOBUF_NDEBUG_INLINE void Swap(InlinedStringField* from,
const std::string* default_value,
Arena* arena, bool donated,
bool from_donated, uint32_t* donating_states,
uint32_t* from_donating_states,
uint32_t mask);
// Frees storage (if not on an arena).
PROTOBUF_NDEBUG_INLINE void Destroy(const std::string* default_value,
Arena* arena) {
if (arena == nullptr) {
DestroyNoArena(default_value);
}
}
PROTOBUF_NDEBUG_INLINE void DestroyNoArena(const std::string* default_value);
// Clears content, but keeps allocated std::string, to avoid the overhead of
// heap operations. After this returns, the content (as seen by the user) will
// always be the empty std::string.
PROTOBUF_NDEBUG_INLINE void ClearToEmpty() { ClearNonDefaultToEmpty(); }
PROTOBUF_NDEBUG_INLINE void ClearNonDefaultToEmpty() {
get_mutable()->clear();
}
// Clears content, but keeps allocated std::string if arena != nullptr, to
// avoid the overhead of heap operations. After this returns, the content (as
// seen by the user) will always be equal to |default_value|.
void ClearToDefault(const LazyString& default_value, Arena* arena,
bool donated);
// Returns a mutable pointer, but doesn't initialize the string to the
// default value.
PROTOBUF_NDEBUG_INLINE std::string* MutableNoArenaNoDefault(
const std::string* /*default_value*/);
// Generated code / reflection only! Returns a mutable pointer to the string.
PROTOBUF_NDEBUG_INLINE std::string* UnsafeMutablePointer();
// InlinedStringField doesn't have things like the `default_value` pointer in
// ArenaStringPtr.
bool IsDefault(const std::string* /*default_value*/) const { return false; }
private:
void Destruct() { get_mutable()->~basic_string(); }
PROTOBUF_NDEBUG_INLINE std::string* get_mutable();
PROTOBUF_NDEBUG_INLINE const std::string* get_const() const;
alignas(std::string) char value_[sizeof(std::string)];
std::string* MutableSlow(::google::protobuf::Arena* arena, bool donated,
uint32_t* donating_states, uint32_t mask);
// When constructed in an Arena, we want our destructor to be skipped.
friend class ::google::protobuf::Arena;
typedef void InternalArenaConstructable_;
typedef void DestructorSkippable_;
};
inline std::string* InlinedStringField::get_mutable() {
return reinterpret_cast<std::string*>(&value_);
}
inline const std::string* InlinedStringField::get_const() const {
return reinterpret_cast<const std::string*>(&value_);
}
inline InlinedStringField::InlinedStringField(
const std::string& default_value) {
new (get_mutable()) std::string(default_value);
}
inline InlinedStringField::InlinedStringField(Arena* arena) {
Init();
if (arena != nullptr) {
arena->OwnDestructor(get_mutable());
}
}
inline const std::string& InlinedStringField::GetNoArena() const {
return *get_const();
}
inline void InlinedStringField::SetAllocatedNoArena(
const std::string* /*default_value*/, std::string* value) {
if (value == nullptr) {
// Currently, inlined string field can't have non empty default.
get_mutable()->clear();
} else {
get_mutable()->assign(std::move(*value));
delete value;
}
}
inline void InlinedStringField::DestroyNoArena(const std::string*) {
// This is invoked from the generated message's ArenaDtor, which is used to
// clean up objects not allocated on the Arena.
this->~InlinedStringField();
}
inline std::string* InlinedStringField::ReleaseNonDefaultNoArena(
const std::string* /*default_value*/) {
// Currently, inlined string field can't have non empty default.
auto* released = new std::string();
get_mutable()->swap(*released);
return released;
}
inline void InlinedStringField::SetNoArena(const std::string* /*default_value*/,
StringPiece value) {
get_mutable()->assign(value.data(), value.length());
}
inline void InlinedStringField::SetNoArena(const std::string* /*default_value*/,
std::string&& value) {
get_mutable()->assign(std::move(value));
}
inline void InlinedStringField::Swap(
InlinedStringField* from, const std::string* /*default_value*/,
Arena* arena, bool donated, bool from_donated, uint32_t* donating_states,
uint32_t* from_donating_states, uint32_t mask) {
#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
// If one is donated and the other is not, undonate the donated one.
if (donated && !from_donated) {
MutableSlow(arena, donated, donating_states, mask);
} else if (!donated && from_donated) {
from->MutableSlow(arena, from_donated, from_donating_states, mask);
}
// Then, swap the two undonated strings.
#else
(void)arena;
(void)donated;
(void)from_donated;
(void)donating_states;
(void)from_donating_states;
(void)mask;
#endif
get_mutable()->swap(*from->get_mutable());
}
inline std::string* InlinedStringField::MutableNoArenaNoDefault(
const std::string*) {
return get_mutable();
}
inline std::string* InlinedStringField::UnsafeMutablePointer() {
return get_mutable();
}
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__
+274 -461
View File
@@ -38,24 +38,17 @@
// will not cross the end of the buffer, since we can avoid a lot
// of branching in this case.
#include <google/protobuf/io/coded_stream.h>
#include <limits.h>
#include <google/protobuf/io/coded_stream_inl.h>
#include <algorithm>
#include <cstring>
#include <utility>
#include <limits.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/stubs/stl_util.h>
#include <google/protobuf/port_def.inc>
namespace google {
namespace protobuf {
namespace io {
@@ -66,8 +59,8 @@ static const int kMaxVarintBytes = 10;
static const int kMaxVarint32Bytes = 5;
inline bool NextNonEmpty(ZeroCopyInputStream* input, const void** data,
int* size) {
inline bool NextNonEmpty(ZeroCopyInputStream* input,
const void** data, int* size) {
bool success;
do {
success = input->Next(data, size);
@@ -89,6 +82,10 @@ CodedInputStream::~CodedInputStream() {
int CodedInputStream::default_recursion_limit_ = 100;
void CodedOutputStream::EnableAliasing(bool enabled) {
aliasing_enabled_ = enabled && output_->AllowsAliasing();
}
void CodedInputStream::BackUpInputToCurrentPosition() {
int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_;
if (backup_bytes > 0) {
@@ -124,9 +121,9 @@ CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) {
// security: byte_limit is possibly evil, so check for negative values
// and overflow. Also check that the new requested limit is before the
// previous limit; otherwise we continue to enforce the previous limit.
if (PROTOBUF_PREDICT_TRUE(byte_limit >= 0 &&
byte_limit <= INT_MAX - current_position &&
byte_limit < current_limit_ - current_position)) {
if GOOGLE_PREDICT_TRUE(byte_limit >= 0 &&
byte_limit <= INT_MAX - current_position &&
byte_limit < current_limit_ - current_position) {
current_limit_ = current_position + byte_limit;
RecomputeBufferLimits();
}
@@ -151,7 +148,7 @@ CodedInputStream::IncrementRecursionDepthAndPushLimit(int byte_limit) {
}
CodedInputStream::Limit CodedInputStream::ReadLengthAndPushLimit() {
uint32_t length;
uint32 length;
return PushLimit(ReadVarint32(&length) ? length : 0);
}
@@ -176,7 +173,10 @@ int CodedInputStream::BytesUntilLimit() const {
return current_limit_ - current_position;
}
void CodedInputStream::SetTotalBytesLimit(int total_bytes_limit) {
void CodedInputStream::SetTotalBytesLimit(
int total_bytes_limit, int warning_threshold) {
(void) warning_threshold;
// Make sure the limit isn't already past, since this could confuse other
// code.
int current_position = CurrentPosition();
@@ -190,13 +190,11 @@ int CodedInputStream::BytesUntilTotalBytesLimit() const {
}
void CodedInputStream::PrintTotalBytesLimitError() {
GOOGLE_LOG(ERROR)
<< "A protocol message was rejected because it was too "
"big (more than "
<< total_bytes_limit_
<< " bytes). To increase the limit (or to disable these "
"warnings), see CodedInputStream::SetTotalBytesLimit() "
"in third_party/protobuf/src/google/protobuf/io/coded_stream.h.";
GOOGLE_LOG(ERROR) << "A protocol message was rejected because it was too "
"big (more than " << total_bytes_limit_
<< " bytes). To increase the limit (or to disable these "
"warnings), see CodedInputStream::SetTotalBytesLimit() "
"in google/protobuf/io/coded_stream.h.";
}
bool CodedInputStream::SkipFallback(int count, int original_buffer_size) {
@@ -222,12 +220,8 @@ bool CodedInputStream::SkipFallback(int count, int original_buffer_size) {
return false;
}
if (!input_->Skip(count)) {
total_bytes_read_ = input_->ByteCount();
return false;
}
total_bytes_read_ += count;
return true;
return input_->Skip(count);
}
bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) {
@@ -239,42 +233,15 @@ bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) {
}
bool CodedInputStream::ReadRaw(void* buffer, int size) {
int current_buffer_size;
while ((current_buffer_size = BufferSize()) < size) {
// Reading past end of buffer. Copy what we have, then refresh.
memcpy(buffer, buffer_, current_buffer_size);
buffer = reinterpret_cast<uint8_t*>(buffer) + current_buffer_size;
size -= current_buffer_size;
Advance(current_buffer_size);
if (!Refresh()) return false;
}
memcpy(buffer, buffer_, size);
Advance(size);
return true;
return InternalReadRawInline(buffer, size);
}
bool CodedInputStream::ReadString(std::string* buffer, int size) {
bool CodedInputStream::ReadString(string* buffer, int size) {
if (size < 0) return false; // security: size is often user-supplied
if (BufferSize() >= size) {
STLStringResizeUninitialized(buffer, size);
std::pair<char*, bool> z = as_string_data(buffer);
if (z.second) {
// Oddly enough, memcpy() requires its first two args to be non-NULL even
// if we copy 0 bytes. So, we have ensured that z.first is non-NULL here.
GOOGLE_DCHECK(z.first != NULL);
memcpy(z.first, buffer_, size);
Advance(size);
}
return true;
}
return ReadStringFallback(buffer, size);
return InternalReadStringInline(buffer, size);
}
bool CodedInputStream::ReadStringFallback(std::string* buffer, int size) {
bool CodedInputStream::ReadStringFallback(string* buffer, int size) {
if (!buffer->empty()) {
buffer->clear();
}
@@ -308,11 +275,11 @@ bool CodedInputStream::ReadStringFallback(std::string* buffer, int size) {
}
bool CodedInputStream::ReadLittleEndian32Fallback(uint32_t* value) {
uint8_t bytes[sizeof(*value)];
bool CodedInputStream::ReadLittleEndian32Fallback(uint32* value) {
uint8 bytes[sizeof(*value)];
const uint8_t* ptr;
if (BufferSize() >= static_cast<int64_t>(sizeof(*value))) {
const uint8* ptr;
if (BufferSize() >= sizeof(*value)) {
// Fast path: Enough bytes in the buffer to read directly.
ptr = buffer_;
Advance(sizeof(*value));
@@ -325,11 +292,11 @@ bool CodedInputStream::ReadLittleEndian32Fallback(uint32_t* value) {
return true;
}
bool CodedInputStream::ReadLittleEndian64Fallback(uint64_t* value) {
uint8_t bytes[sizeof(*value)];
bool CodedInputStream::ReadLittleEndian64Fallback(uint64* value) {
uint8 bytes[sizeof(*value)];
const uint8_t* ptr;
if (BufferSize() >= static_cast<int64_t>(sizeof(*value))) {
const uint8* ptr;
if (BufferSize() >= sizeof(*value)) {
// Fast path: Enough bytes in the buffer to read directly.
ptr = buffer_;
Advance(sizeof(*value));
@@ -344,126 +311,111 @@ bool CodedInputStream::ReadLittleEndian64Fallback(uint64_t* value) {
namespace {
// Decodes varint64 with known size, N, and returns next pointer. Knowing N at
// compile time, compiler can generate optimal code. For example, instead of
// subtracting 0x80 at each iteration, it subtracts properly shifted mask once.
template <size_t N>
const uint8_t* DecodeVarint64KnownSize(const uint8_t* buffer, uint64_t* value) {
GOOGLE_DCHECK_GT(N, 0);
uint64_t result = static_cast<uint64_t>(buffer[N - 1]) << (7 * (N - 1));
for (size_t i = 0, offset = 0; i < N - 1; i++, offset += 7) {
result += static_cast<uint64_t>(buffer[i] - 0x80) << offset;
}
*value = result;
return buffer + N;
}
// Read a varint from the given buffer, write it to *value, and return a pair.
// The first part of the pair is true iff the read was successful. The second
// part is buffer + (number of bytes read). This function is always inlined,
// so returning a pair is costless.
PROTOBUF_ALWAYS_INLINE
::std::pair<bool, const uint8_t*> ReadVarint32FromArray(uint32_t first_byte,
const uint8_t* buffer,
uint32_t* value);
inline ::std::pair<bool, const uint8_t*> ReadVarint32FromArray(
uint32_t first_byte, const uint8_t* buffer, uint32_t* value) {
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
::std::pair<bool, const uint8*> ReadVarint32FromArray(
uint32 first_byte, const uint8* buffer,
uint32* value);
inline ::std::pair<bool, const uint8*> ReadVarint32FromArray(
uint32 first_byte, const uint8* buffer, uint32* value) {
// Fast path: We have enough bytes left in the buffer to guarantee that
// this read won't cross the end, so we can skip the checks.
GOOGLE_DCHECK_EQ(*buffer, first_byte);
GOOGLE_DCHECK_EQ(first_byte & 0x80, 0x80) << first_byte;
const uint8_t* ptr = buffer;
uint32_t b;
uint32_t result = first_byte - 0x80;
const uint8* ptr = buffer;
uint32 b;
uint32 result = first_byte - 0x80;
++ptr; // We just processed the first byte. Move on to the second.
b = *(ptr++);
result += b << 7;
if (!(b & 0x80)) goto done;
b = *(ptr++); result += b << 7; if (!(b & 0x80)) goto done;
result -= 0x80 << 7;
b = *(ptr++);
result += b << 14;
if (!(b & 0x80)) goto done;
b = *(ptr++); result += b << 14; if (!(b & 0x80)) goto done;
result -= 0x80 << 14;
b = *(ptr++);
result += b << 21;
if (!(b & 0x80)) goto done;
b = *(ptr++); result += b << 21; if (!(b & 0x80)) goto done;
result -= 0x80 << 21;
b = *(ptr++);
result += b << 28;
if (!(b & 0x80)) goto done;
b = *(ptr++); result += b << 28; if (!(b & 0x80)) goto done;
// "result -= 0x80 << 28" is irrevelant.
// If the input is larger than 32 bits, we still need to read it all
// and discard the high-order bits.
for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) {
b = *(ptr++);
if (!(b & 0x80)) goto done;
b = *(ptr++); if (!(b & 0x80)) goto done;
}
// We have overrun the maximum size of a varint (10 bytes). Assume
// the data is corrupt.
return std::make_pair(false, ptr);
done:
done:
*value = result;
return std::make_pair(true, ptr);
}
PROTOBUF_ALWAYS_INLINE::std::pair<bool, const uint8_t*> ReadVarint64FromArray(
const uint8_t* buffer, uint64_t* value);
inline ::std::pair<bool, const uint8_t*> ReadVarint64FromArray(
const uint8_t* buffer, uint64_t* value) {
// Assumes varint64 is at least 2 bytes.
GOOGLE_DCHECK_GE(buffer[0], 128);
GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE::std::pair<bool, const uint8*>
ReadVarint64FromArray(const uint8* buffer, uint64* value);
inline ::std::pair<bool, const uint8*> ReadVarint64FromArray(
const uint8* buffer, uint64* value) {
const uint8* ptr = buffer;
uint32 b;
const uint8_t* next;
if (buffer[1] < 128) {
next = DecodeVarint64KnownSize<2>(buffer, value);
} else if (buffer[2] < 128) {
next = DecodeVarint64KnownSize<3>(buffer, value);
} else if (buffer[3] < 128) {
next = DecodeVarint64KnownSize<4>(buffer, value);
} else if (buffer[4] < 128) {
next = DecodeVarint64KnownSize<5>(buffer, value);
} else if (buffer[5] < 128) {
next = DecodeVarint64KnownSize<6>(buffer, value);
} else if (buffer[6] < 128) {
next = DecodeVarint64KnownSize<7>(buffer, value);
} else if (buffer[7] < 128) {
next = DecodeVarint64KnownSize<8>(buffer, value);
} else if (buffer[8] < 128) {
next = DecodeVarint64KnownSize<9>(buffer, value);
} else if (buffer[9] < 128) {
next = DecodeVarint64KnownSize<10>(buffer, value);
} else {
// We have overrun the maximum size of a varint (10 bytes). Assume
// the data is corrupt.
return std::make_pair(false, buffer + 11);
}
// Splitting into 32-bit pieces gives better performance on 32-bit
// processors.
uint32 part0 = 0, part1 = 0, part2 = 0;
return std::make_pair(true, next);
b = *(ptr++); part0 = b ; if (!(b & 0x80)) goto done;
part0 -= 0x80;
b = *(ptr++); part0 += b << 7; if (!(b & 0x80)) goto done;
part0 -= 0x80 << 7;
b = *(ptr++); part0 += b << 14; if (!(b & 0x80)) goto done;
part0 -= 0x80 << 14;
b = *(ptr++); part0 += b << 21; if (!(b & 0x80)) goto done;
part0 -= 0x80 << 21;
b = *(ptr++); part1 = b ; if (!(b & 0x80)) goto done;
part1 -= 0x80;
b = *(ptr++); part1 += b << 7; if (!(b & 0x80)) goto done;
part1 -= 0x80 << 7;
b = *(ptr++); part1 += b << 14; if (!(b & 0x80)) goto done;
part1 -= 0x80 << 14;
b = *(ptr++); part1 += b << 21; if (!(b & 0x80)) goto done;
part1 -= 0x80 << 21;
b = *(ptr++); part2 = b ; if (!(b & 0x80)) goto done;
part2 -= 0x80;
b = *(ptr++); part2 += b << 7; if (!(b & 0x80)) goto done;
// "part2 -= 0x80 << 7" is irrelevant because (0x80 << 7) << 56 is 0.
// We have overrun the maximum size of a varint (10 bytes). Assume
// the data is corrupt.
return std::make_pair(false, ptr);
done:
*value = (static_cast<uint64>(part0)) |
(static_cast<uint64>(part1) << 28) |
(static_cast<uint64>(part2) << 56);
return std::make_pair(true, ptr);
}
} // namespace
bool CodedInputStream::ReadVarint32Slow(uint32_t* value) {
bool CodedInputStream::ReadVarint32Slow(uint32* value) {
// Directly invoke ReadVarint64Fallback, since we already tried to optimize
// for one-byte varints.
std::pair<uint64_t, bool> p = ReadVarint64Fallback();
*value = static_cast<uint32_t>(p.first);
std::pair<uint64, bool> p = ReadVarint64Fallback();
*value = static_cast<uint32>(p.first);
return p.second;
}
int64_t CodedInputStream::ReadVarint32Fallback(uint32_t first_byte_or_zero) {
int64 CodedInputStream::ReadVarint32Fallback(uint32 first_byte_or_zero) {
if (BufferSize() >= kMaxVarintBytes ||
// Optimization: We're also safe if the buffer is non-empty and it ends
// with a byte that would terminate a varint.
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
GOOGLE_DCHECK_NE(first_byte_or_zero, 0)
<< "Caller should provide us with *buffer_ when buffer is non-empty";
uint32_t temp;
::std::pair<bool, const uint8_t*> p =
ReadVarint32FromArray(first_byte_or_zero, buffer_, &temp);
uint32 temp;
::std::pair<bool, const uint8*> p =
ReadVarint32FromArray(first_byte_or_zero, buffer_, &temp);
if (!p.first) return -1;
buffer_ = p.second;
return temp;
@@ -471,16 +423,16 @@ int64_t CodedInputStream::ReadVarint32Fallback(uint32_t first_byte_or_zero) {
// Really slow case: we will incur the cost of an extra function call here,
// but moving this out of line reduces the size of this function, which
// improves the common case. In micro benchmarks, this is worth about 10-15%
uint32_t temp;
return ReadVarint32Slow(&temp) ? static_cast<int64_t>(temp) : -1;
uint32 temp;
return ReadVarint32Slow(&temp) ? static_cast<int64>(temp) : -1;
}
}
int CodedInputStream::ReadVarintSizeAsIntSlow() {
// Directly invoke ReadVarint64Fallback, since we already tried to optimize
// for one-byte varints.
std::pair<uint64_t, bool> p = ReadVarint64Fallback();
if (!p.second || p.first > static_cast<uint64_t>(INT_MAX)) return -1;
std::pair<uint64, bool> p = ReadVarint64Fallback();
if (!p.second || p.first > static_cast<uint64>(INT_MAX)) return -1;
return p.first;
}
@@ -489,9 +441,9 @@ int CodedInputStream::ReadVarintSizeAsIntFallback() {
// Optimization: We're also safe if the buffer is non-empty and it ends
// with a byte that would terminate a varint.
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
uint64_t temp;
::std::pair<bool, const uint8_t*> p = ReadVarint64FromArray(buffer_, &temp);
if (!p.first || temp > static_cast<uint64_t>(INT_MAX)) return -1;
uint64 temp;
::std::pair<bool, const uint8*> p = ReadVarint64FromArray(buffer_, &temp);
if (!p.first || temp > static_cast<uint64>(INT_MAX)) return -1;
buffer_ = p.second;
return temp;
} else {
@@ -502,7 +454,7 @@ int CodedInputStream::ReadVarintSizeAsIntFallback() {
}
}
uint32_t CodedInputStream::ReadTagSlow() {
uint32 CodedInputStream::ReadTagSlow() {
if (buffer_ == buffer_end_) {
// Call refresh.
if (!Refresh()) {
@@ -523,12 +475,12 @@ uint32_t CodedInputStream::ReadTagSlow() {
// For the slow path, just do a 64-bit read. Try to optimize for one-byte tags
// again, since we have now refreshed the buffer.
uint64_t result = 0;
uint64 result = 0;
if (!ReadVarint64(&result)) return 0;
return static_cast<uint32_t>(result);
return static_cast<uint32>(result);
}
uint32_t CodedInputStream::ReadTagFallback(uint32_t first_byte_or_zero) {
uint32 CodedInputStream::ReadTagFallback(uint32 first_byte_or_zero) {
const int buf_size = BufferSize();
if (buf_size >= kMaxVarintBytes ||
// Optimization: We're also safe if the buffer is non-empty and it ends
@@ -539,8 +491,8 @@ uint32_t CodedInputStream::ReadTagFallback(uint32_t first_byte_or_zero) {
++buffer_;
return 0;
}
uint32_t tag;
::std::pair<bool, const uint8_t*> p =
uint32 tag;
::std::pair<bool, const uint8*> p =
ReadVarint32FromArray(first_byte_or_zero, buffer_, &tag);
if (!p.first) {
return 0;
@@ -565,13 +517,13 @@ uint32_t CodedInputStream::ReadTagFallback(uint32_t first_byte_or_zero) {
}
}
bool CodedInputStream::ReadVarint64Slow(uint64_t* value) {
bool CodedInputStream::ReadVarint64Slow(uint64* value) {
// Slow path: This read might cross the end of the buffer, so we
// need to check and refresh the buffer if and when it does.
uint64_t result = 0;
uint64 result = 0;
int count = 0;
uint32_t b;
uint32 b;
do {
if (count == kMaxVarintBytes) {
@@ -585,7 +537,7 @@ bool CodedInputStream::ReadVarint64Slow(uint64_t* value) {
}
}
b = *buffer_;
result |= static_cast<uint64_t>(b & 0x7F) << (7 * count);
result |= static_cast<uint64>(b & 0x7F) << (7 * count);
Advance(1);
++count;
} while (b & 0x80);
@@ -594,20 +546,20 @@ bool CodedInputStream::ReadVarint64Slow(uint64_t* value) {
return true;
}
std::pair<uint64_t, bool> CodedInputStream::ReadVarint64Fallback() {
std::pair<uint64, bool> CodedInputStream::ReadVarint64Fallback() {
if (BufferSize() >= kMaxVarintBytes ||
// Optimization: We're also safe if the buffer is non-empty and it ends
// with a byte that would terminate a varint.
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
uint64_t temp;
::std::pair<bool, const uint8_t*> p = ReadVarint64FromArray(buffer_, &temp);
uint64 temp;
::std::pair<bool, const uint8*> p = ReadVarint64FromArray(buffer_, &temp);
if (!p.first) {
return std::make_pair(0, false);
}
buffer_ = p.second;
return std::make_pair(temp, true);
} else {
uint64_t temp;
uint64 temp;
bool success = ReadVarint64Slow(&temp);
return std::make_pair(temp, success);
}
@@ -633,7 +585,7 @@ bool CodedInputStream::Refresh() {
const void* void_buffer;
int buffer_size;
if (NextNonEmpty(input_, &void_buffer, &buffer_size)) {
buffer_ = reinterpret_cast<const uint8_t*>(void_buffer);
buffer_ = reinterpret_cast<const uint8*>(void_buffer);
buffer_end_ = buffer_ + buffer_size;
GOOGLE_CHECK_GE(buffer_size, 0);
@@ -666,313 +618,174 @@ bool CodedInputStream::Refresh() {
// CodedOutputStream =================================================
void EpsCopyOutputStream::EnableAliasing(bool enabled) {
aliasing_enabled_ = enabled && stream_->AllowsAliasing();
google::protobuf::internal::AtomicWord CodedOutputStream::default_serialization_deterministic_ = 0;
CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
: output_(output),
buffer_(NULL),
buffer_size_(0),
total_bytes_(0),
had_error_(false),
aliasing_enabled_(false),
serialization_deterministic_is_overridden_(false) {
// Eagerly Refresh() so buffer space is immediately available.
Refresh();
// The Refresh() may have failed. If the client doesn't write any data,
// though, don't consider this an error. If the client does write data, then
// another Refresh() will be attempted and it will set the error once again.
had_error_ = false;
}
int64_t EpsCopyOutputStream::ByteCount(uint8_t* ptr) const {
// Calculate the current offset relative to the end of the stream buffer.
int delta = (end_ - ptr) + (buffer_end_ ? 0 : kSlopBytes);
return stream_->ByteCount() - delta;
}
// Flushes what's written out to the underlying ZeroCopyOutputStream buffers.
// Returns the size remaining in the buffer and sets buffer_end_ to the start
// of the remaining buffer, ie. [buffer_end_, buffer_end_ + return value)
int EpsCopyOutputStream::Flush(uint8_t* ptr) {
while (buffer_end_ && ptr > end_) {
int overrun = ptr - end_;
GOOGLE_DCHECK(!had_error_);
GOOGLE_DCHECK(overrun <= kSlopBytes); // NOLINT
ptr = Next() + overrun;
if (had_error_) return 0;
}
int s;
if (buffer_end_) {
std::memcpy(buffer_end_, buffer_, ptr - buffer_);
buffer_end_ += ptr - buffer_;
s = end_ - ptr;
} else {
// The stream is writing directly in the ZeroCopyOutputStream buffer.
s = end_ + kSlopBytes - ptr;
buffer_end_ = ptr;
}
GOOGLE_DCHECK(s >= 0); // NOLINT
return s;
}
uint8_t* EpsCopyOutputStream::Trim(uint8_t* ptr) {
if (had_error_) return ptr;
int s = Flush(ptr);
if (s) stream_->BackUp(s);
// Reset to initial state (expecting new buffer)
buffer_end_ = end_ = buffer_;
return buffer_;
}
uint8_t* EpsCopyOutputStream::FlushAndResetBuffer(uint8_t* ptr) {
if (had_error_) return buffer_;
int s = Flush(ptr);
if (had_error_) return buffer_;
return SetInitialBuffer(buffer_end_, s);
}
bool EpsCopyOutputStream::Skip(int count, uint8_t** pp) {
if (count < 0) return false;
if (had_error_) {
*pp = buffer_;
return false;
}
int size = Flush(*pp);
if (had_error_) {
*pp = buffer_;
return false;
}
void* data = buffer_end_;
while (count > size) {
count -= size;
if (!stream_->Next(&data, &size)) {
*pp = Error();
return false;
}
}
*pp = SetInitialBuffer(static_cast<uint8_t*>(data) + count, size - count);
return true;
}
bool EpsCopyOutputStream::GetDirectBufferPointer(void** data, int* size,
uint8_t** pp) {
if (had_error_) {
*pp = buffer_;
return false;
}
*size = Flush(*pp);
if (had_error_) {
*pp = buffer_;
return false;
}
*data = buffer_end_;
while (*size == 0) {
if (!stream_->Next(data, size)) {
*pp = Error();
return false;
}
}
*pp = SetInitialBuffer(*data, *size);
return true;
}
uint8_t* EpsCopyOutputStream::GetDirectBufferForNBytesAndAdvance(int size,
uint8_t** pp) {
if (had_error_) {
*pp = buffer_;
return nullptr;
}
int s = Flush(*pp);
if (had_error_) {
*pp = buffer_;
return nullptr;
}
if (s >= size) {
auto res = buffer_end_;
*pp = SetInitialBuffer(buffer_end_ + size, s - size);
return res;
} else {
*pp = SetInitialBuffer(buffer_end_, s);
return nullptr;
}
}
uint8_t* EpsCopyOutputStream::Next() {
GOOGLE_DCHECK(!had_error_); // NOLINT
if (PROTOBUF_PREDICT_FALSE(stream_ == nullptr)) return Error();
if (buffer_end_) {
// We're in the patch buffer and need to fill up the previous buffer.
std::memcpy(buffer_end_, buffer_, end_ - buffer_);
uint8_t* ptr;
int size;
do {
void* data;
if (PROTOBUF_PREDICT_FALSE(!stream_->Next(&data, &size))) {
// Stream has an error, we use the patch buffer to continue to be
// able to write.
return Error();
}
ptr = static_cast<uint8_t*>(data);
} while (size == 0);
if (PROTOBUF_PREDICT_TRUE(size > kSlopBytes)) {
std::memcpy(ptr, end_, kSlopBytes);
end_ = ptr + size - kSlopBytes;
buffer_end_ = nullptr;
return ptr;
} else {
GOOGLE_DCHECK(size > 0); // NOLINT
// Buffer to small
std::memmove(buffer_, end_, kSlopBytes);
buffer_end_ = ptr;
end_ = buffer_ + size;
return buffer_;
}
} else {
std::memcpy(buffer_, end_, kSlopBytes);
buffer_end_ = end_;
end_ = buffer_ + kSlopBytes;
return buffer_;
}
}
uint8_t* EpsCopyOutputStream::EnsureSpaceFallback(uint8_t* ptr) {
do {
if (PROTOBUF_PREDICT_FALSE(had_error_)) return buffer_;
int overrun = ptr - end_;
GOOGLE_DCHECK(overrun >= 0); // NOLINT
GOOGLE_DCHECK(overrun <= kSlopBytes); // NOLINT
ptr = Next() + overrun;
} while (ptr >= end_);
GOOGLE_DCHECK(ptr < end_); // NOLINT
return ptr;
}
uint8_t* EpsCopyOutputStream::WriteRawFallback(const void* data, int size,
uint8_t* ptr) {
int s = GetSize(ptr);
while (s < size) {
std::memcpy(ptr, data, s);
size -= s;
data = static_cast<const uint8_t*>(data) + s;
ptr = EnsureSpaceFallback(ptr + s);
s = GetSize(ptr);
}
std::memcpy(ptr, data, size);
return ptr + size;
}
uint8_t* EpsCopyOutputStream::WriteAliasedRaw(const void* data, int size,
uint8_t* ptr) {
if (size < GetSize(ptr)
) {
return WriteRaw(data, size, ptr);
} else {
ptr = Trim(ptr);
if (stream_->WriteAliasedRaw(data, size)) return ptr;
return Error();
}
}
#ifndef PROTOBUF_LITTLE_ENDIAN
uint8_t* EpsCopyOutputStream::WriteRawLittleEndian32(const void* data, int size,
uint8_t* ptr) {
auto p = static_cast<const uint8_t*>(data);
auto end = p + size;
while (end - p >= kSlopBytes) {
ptr = EnsureSpace(ptr);
uint32_t buffer[4];
static_assert(sizeof(buffer) == kSlopBytes, "Buffer must be kSlopBytes");
std::memcpy(buffer, p, kSlopBytes);
p += kSlopBytes;
for (auto x : buffer)
ptr = CodedOutputStream::WriteLittleEndian32ToArray(x, ptr);
}
while (p < end) {
ptr = EnsureSpace(ptr);
uint32_t buffer;
std::memcpy(&buffer, p, 4);
p += 4;
ptr = CodedOutputStream::WriteLittleEndian32ToArray(buffer, ptr);
}
return ptr;
}
uint8_t* EpsCopyOutputStream::WriteRawLittleEndian64(const void* data, int size,
uint8_t* ptr) {
auto p = static_cast<const uint8_t*>(data);
auto end = p + size;
while (end - p >= kSlopBytes) {
ptr = EnsureSpace(ptr);
uint64_t buffer[2];
static_assert(sizeof(buffer) == kSlopBytes, "Buffer must be kSlopBytes");
std::memcpy(buffer, p, kSlopBytes);
p += kSlopBytes;
for (auto x : buffer)
ptr = CodedOutputStream::WriteLittleEndian64ToArray(x, ptr);
}
while (p < end) {
ptr = EnsureSpace(ptr);
uint64_t buffer;
std::memcpy(&buffer, p, 8);
p += 8;
ptr = CodedOutputStream::WriteLittleEndian64ToArray(buffer, ptr);
}
return ptr;
}
#endif
uint8_t* EpsCopyOutputStream::WriteStringMaybeAliasedOutline(uint32_t num,
const std::string& s,
uint8_t* ptr) {
ptr = EnsureSpace(ptr);
uint32_t size = s.size();
ptr = WriteLengthDelim(num, size, ptr);
return WriteRawMaybeAliased(s.data(), size, ptr);
}
uint8_t* EpsCopyOutputStream::WriteStringOutline(uint32_t num, const std::string& s,
uint8_t* ptr) {
ptr = EnsureSpace(ptr);
uint32_t size = s.size();
ptr = WriteLengthDelim(num, size, ptr);
return WriteRaw(s.data(), size, ptr);
}
std::atomic<bool> CodedOutputStream::default_serialization_deterministic_{
false};
CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* stream,
CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output,
bool do_eager_refresh)
: impl_(stream, IsDefaultSerializationDeterministic(), &cur_),
start_count_(stream->ByteCount()) {
: output_(output),
buffer_(NULL),
buffer_size_(0),
total_bytes_(0),
had_error_(false),
aliasing_enabled_(false),
serialization_deterministic_is_overridden_(false) {
if (do_eager_refresh) {
void* data;
int size;
if (!stream->Next(&data, &size) || size == 0) return;
cur_ = impl_.SetInitialBuffer(data, size);
// Eagerly Refresh() so buffer space is immediately available.
Refresh();
// The Refresh() may have failed. If the client doesn't write any data,
// though, don't consider this an error. If the client does write data, then
// another Refresh() will be attempted and it will set the error once again.
had_error_ = false;
}
}
CodedOutputStream::~CodedOutputStream() { Trim(); }
CodedOutputStream::~CodedOutputStream() {
Trim();
}
void CodedOutputStream::Trim() {
if (buffer_size_ > 0) {
output_->BackUp(buffer_size_);
total_bytes_ -= buffer_size_;
buffer_size_ = 0;
buffer_ = NULL;
}
}
bool CodedOutputStream::Skip(int count) {
if (count < 0) return false;
while (count > buffer_size_) {
count -= buffer_size_;
if (!Refresh()) return false;
}
Advance(count);
return true;
}
bool CodedOutputStream::GetDirectBufferPointer(void** data, int* size) {
if (buffer_size_ == 0 && !Refresh()) return false;
*data = buffer_;
*size = buffer_size_;
return true;
}
void CodedOutputStream::WriteRaw(const void* data, int size) {
while (buffer_size_ < size) {
memcpy(buffer_, data, buffer_size_);
size -= buffer_size_;
data = reinterpret_cast<const uint8*>(data) + buffer_size_;
if (!Refresh()) return;
}
memcpy(buffer_, data, size);
Advance(size);
}
uint8* CodedOutputStream::WriteRawToArray(
const void* data, int size, uint8* target) {
memcpy(target, data, size);
return target + size;
}
uint8_t* CodedOutputStream::WriteStringWithSizeToArray(const std::string& str,
uint8_t* target) {
GOOGLE_DCHECK_LE(str.size(), std::numeric_limits<uint32_t>::max());
void CodedOutputStream::WriteAliasedRaw(const void* data, int size) {
if (size < buffer_size_
) {
WriteRaw(data, size);
} else {
Trim();
total_bytes_ += size;
had_error_ |= !output_->WriteAliasedRaw(data, size);
}
}
void CodedOutputStream::WriteLittleEndian32(uint32 value) {
uint8 bytes[sizeof(value)];
bool use_fast = buffer_size_ >= sizeof(value);
uint8* ptr = use_fast ? buffer_ : bytes;
WriteLittleEndian32ToArray(value, ptr);
if (use_fast) {
Advance(sizeof(value));
} else {
WriteRaw(bytes, sizeof(value));
}
}
void CodedOutputStream::WriteLittleEndian64(uint64 value) {
uint8 bytes[sizeof(value)];
bool use_fast = buffer_size_ >= sizeof(value);
uint8* ptr = use_fast ? buffer_ : bytes;
WriteLittleEndian64ToArray(value, ptr);
if (use_fast) {
Advance(sizeof(value));
} else {
WriteRaw(bytes, sizeof(value));
}
}
void CodedOutputStream::WriteVarint32SlowPath(uint32 value) {
uint8 bytes[kMaxVarint32Bytes];
uint8* target = &bytes[0];
uint8* end = WriteVarint32ToArray(value, target);
int size = end - target;
WriteRaw(bytes, size);
}
void CodedOutputStream::WriteVarint64SlowPath(uint64 value) {
uint8 bytes[kMaxVarintBytes];
uint8* target = &bytes[0];
uint8* end = WriteVarint64ToArray(value, target);
int size = end - target;
WriteRaw(bytes, size);
}
bool CodedOutputStream::Refresh() {
void* void_buffer;
if (output_->Next(&void_buffer, &buffer_size_)) {
buffer_ = reinterpret_cast<uint8*>(void_buffer);
total_bytes_ += buffer_size_;
return true;
} else {
buffer_ = NULL;
buffer_size_ = 0;
had_error_ = true;
return false;
}
}
uint8* CodedOutputStream::WriteStringWithSizeToArray(const string& str,
uint8* target) {
GOOGLE_DCHECK_LE(str.size(), kuint32max);
target = WriteVarint32ToArray(str.size(), target);
return WriteStringToArray(str, target);
}
uint8_t* CodedOutputStream::WriteVarint32ToArrayOutOfLineHelper(uint32_t value,
uint8_t* target) {
GOOGLE_DCHECK_GE(value, 0x80);
target[0] |= static_cast<uint8_t>(0x80);
value >>= 7;
target[1] = static_cast<uint8_t>(value);
if (value < 0x80) {
return target + 2;
}
target += 2;
do {
// Turn on continuation bit in the byte we just wrote.
target[-1] |= static_cast<uint8_t>(0x80);
value >>= 7;
*target = static_cast<uint8_t>(value);
++target;
} while (value >= 0x80);
return target;
}
} // namespace io
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,90 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: jasonh@google.com (Jason Hsueh)
//
// Implements methods of coded_stream.h that need to be inlined for performance
// reasons, but should not be defined in a public header.
#ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__
#define GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <string>
#include <google/protobuf/stubs/stl_util.h>
namespace google {
namespace protobuf {
namespace io {
inline bool CodedInputStream::InternalReadStringInline(string* buffer,
int size) {
if (size < 0) return false; // security: size is often user-supplied
if (BufferSize() >= size) {
STLStringResizeUninitialized(buffer, size);
std::pair<char*, bool> z = as_string_data(buffer);
if (z.second) {
// Oddly enough, memcpy() requires its first two args to be non-NULL even
// if we copy 0 bytes. So, we have ensured that z.first is non-NULL here.
GOOGLE_DCHECK(z.first != NULL);
memcpy(z.first, buffer_, size);
Advance(size);
}
return true;
}
return ReadStringFallback(buffer, size);
}
inline bool CodedInputStream::InternalReadRawInline(void* buffer, int size) {
int current_buffer_size;
while ((current_buffer_size = BufferSize()) < size) {
// Reading past end of buffer. Copy what we have, then refresh.
memcpy(buffer, buffer_, current_buffer_size);
buffer = reinterpret_cast<uint8*>(buffer) + current_buffer_size;
size -= current_buffer_size;
Advance(current_buffer_size);
if (!Refresh()) return false;
}
memcpy(buffer, buffer_, size);
Advance(size);
return true;
}
} // namespace io
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__
+330
View File
@@ -0,0 +1,330 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: brianolson@google.com (Brian Olson)
//
// This file contains the implementation of classes GzipInputStream and
// GzipOutputStream.
#if HAVE_ZLIB
#include <google/protobuf/io/gzip_stream.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/logging.h>
namespace google {
namespace protobuf {
namespace io {
static const int kDefaultBufferSize = 65536;
GzipInputStream::GzipInputStream(
ZeroCopyInputStream* sub_stream, Format format, int buffer_size)
: format_(format), sub_stream_(sub_stream), zerror_(Z_OK), byte_count_(0) {
zcontext_.state = Z_NULL;
zcontext_.zalloc = Z_NULL;
zcontext_.zfree = Z_NULL;
zcontext_.opaque = Z_NULL;
zcontext_.total_out = 0;
zcontext_.next_in = NULL;
zcontext_.avail_in = 0;
zcontext_.total_in = 0;
zcontext_.msg = NULL;
if (buffer_size == -1) {
output_buffer_length_ = kDefaultBufferSize;
} else {
output_buffer_length_ = buffer_size;
}
output_buffer_ = operator new(output_buffer_length_);
GOOGLE_CHECK(output_buffer_ != NULL);
zcontext_.next_out = static_cast<Bytef*>(output_buffer_);
zcontext_.avail_out = output_buffer_length_;
output_position_ = output_buffer_;
}
GzipInputStream::~GzipInputStream() {
operator delete(output_buffer_);
zerror_ = inflateEnd(&zcontext_);
}
static inline int internalInflateInit2(
z_stream* zcontext, GzipInputStream::Format format) {
int windowBitsFormat = 0;
switch (format) {
case GzipInputStream::GZIP: windowBitsFormat = 16; break;
case GzipInputStream::AUTO: windowBitsFormat = 32; break;
case GzipInputStream::ZLIB: windowBitsFormat = 0; break;
}
return inflateInit2(zcontext, /* windowBits */15 | windowBitsFormat);
}
int GzipInputStream::Inflate(int flush) {
if ((zerror_ == Z_OK) && (zcontext_.avail_out == 0)) {
// previous inflate filled output buffer. don't change input params yet.
} else if (zcontext_.avail_in == 0) {
const void* in;
int in_size;
bool first = zcontext_.next_in == NULL;
bool ok = sub_stream_->Next(&in, &in_size);
if (!ok) {
zcontext_.next_out = NULL;
zcontext_.avail_out = 0;
return Z_STREAM_END;
}
zcontext_.next_in = static_cast<Bytef*>(const_cast<void*>(in));
zcontext_.avail_in = in_size;
if (first) {
int error = internalInflateInit2(&zcontext_, format_);
if (error != Z_OK) {
return error;
}
}
}
zcontext_.next_out = static_cast<Bytef*>(output_buffer_);
zcontext_.avail_out = output_buffer_length_;
output_position_ = output_buffer_;
int error = inflate(&zcontext_, flush);
return error;
}
void GzipInputStream::DoNextOutput(const void** data, int* size) {
*data = output_position_;
*size = ((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_);
output_position_ = zcontext_.next_out;
}
// implements ZeroCopyInputStream ----------------------------------
bool GzipInputStream::Next(const void** data, int* size) {
bool ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END)
|| (zerror_ == Z_BUF_ERROR);
if ((!ok) || (zcontext_.next_out == NULL)) {
return false;
}
if (zcontext_.next_out != output_position_) {
DoNextOutput(data, size);
return true;
}
if (zerror_ == Z_STREAM_END) {
if (zcontext_.next_out != NULL) {
// sub_stream_ may have concatenated streams to follow
zerror_ = inflateEnd(&zcontext_);
byte_count_ += zcontext_.total_out;
if (zerror_ != Z_OK) {
return false;
}
zerror_ = internalInflateInit2(&zcontext_, format_);
if (zerror_ != Z_OK) {
return false;
}
} else {
*data = NULL;
*size = 0;
return false;
}
}
zerror_ = Inflate(Z_NO_FLUSH);
if ((zerror_ == Z_STREAM_END) && (zcontext_.next_out == NULL)) {
// The underlying stream's Next returned false inside Inflate.
return false;
}
ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END)
|| (zerror_ == Z_BUF_ERROR);
if (!ok) {
return false;
}
DoNextOutput(data, size);
return true;
}
void GzipInputStream::BackUp(int count) {
output_position_ = reinterpret_cast<void*>(
reinterpret_cast<uintptr_t>(output_position_) - count);
}
bool GzipInputStream::Skip(int count) {
const void* data;
int size = 0;
bool ok = Next(&data, &size);
while (ok && (size < count)) {
count -= size;
ok = Next(&data, &size);
}
if (size > count) {
BackUp(size - count);
}
return ok;
}
int64 GzipInputStream::ByteCount() const {
int64 ret = byte_count_ + zcontext_.total_out;
if (zcontext_.next_out != NULL && output_position_ != NULL) {
ret += reinterpret_cast<uintptr_t>(zcontext_.next_out) -
reinterpret_cast<uintptr_t>(output_position_);
}
return ret;
}
// =========================================================================
GzipOutputStream::Options::Options()
: format(GZIP),
buffer_size(kDefaultBufferSize),
compression_level(Z_DEFAULT_COMPRESSION),
compression_strategy(Z_DEFAULT_STRATEGY) {}
GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream) {
Init(sub_stream, Options());
}
GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream,
const Options& options) {
Init(sub_stream, options);
}
void GzipOutputStream::Init(ZeroCopyOutputStream* sub_stream,
const Options& options) {
sub_stream_ = sub_stream;
sub_data_ = NULL;
sub_data_size_ = 0;
input_buffer_length_ = options.buffer_size;
input_buffer_ = operator new(input_buffer_length_);
GOOGLE_CHECK(input_buffer_ != NULL);
zcontext_.zalloc = Z_NULL;
zcontext_.zfree = Z_NULL;
zcontext_.opaque = Z_NULL;
zcontext_.next_out = NULL;
zcontext_.avail_out = 0;
zcontext_.total_out = 0;
zcontext_.next_in = NULL;
zcontext_.avail_in = 0;
zcontext_.total_in = 0;
zcontext_.msg = NULL;
// default to GZIP format
int windowBitsFormat = 16;
if (options.format == ZLIB) {
windowBitsFormat = 0;
}
zerror_ = deflateInit2(
&zcontext_,
options.compression_level,
Z_DEFLATED,
/* windowBits */15 | windowBitsFormat,
/* memLevel (default) */8,
options.compression_strategy);
}
GzipOutputStream::~GzipOutputStream() {
Close();
operator delete(input_buffer_);
}
// private
int GzipOutputStream::Deflate(int flush) {
int error = Z_OK;
do {
if ((sub_data_ == NULL) || (zcontext_.avail_out == 0)) {
bool ok = sub_stream_->Next(&sub_data_, &sub_data_size_);
if (!ok) {
sub_data_ = NULL;
sub_data_size_ = 0;
return Z_BUF_ERROR;
}
GOOGLE_CHECK_GT(sub_data_size_, 0);
zcontext_.next_out = static_cast<Bytef*>(sub_data_);
zcontext_.avail_out = sub_data_size_;
}
error = deflate(&zcontext_, flush);
} while (error == Z_OK && zcontext_.avail_out == 0);
if ((flush == Z_FULL_FLUSH) || (flush == Z_FINISH)) {
// Notify lower layer of data.
sub_stream_->BackUp(zcontext_.avail_out);
// We don't own the buffer anymore.
sub_data_ = NULL;
sub_data_size_ = 0;
}
return error;
}
// implements ZeroCopyOutputStream ---------------------------------
bool GzipOutputStream::Next(void** data, int* size) {
if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) {
return false;
}
if (zcontext_.avail_in != 0) {
zerror_ = Deflate(Z_NO_FLUSH);
if (zerror_ != Z_OK) {
return false;
}
}
if (zcontext_.avail_in == 0) {
// all input was consumed. reset the buffer.
zcontext_.next_in = static_cast<Bytef*>(input_buffer_);
zcontext_.avail_in = input_buffer_length_;
*data = input_buffer_;
*size = input_buffer_length_;
} else {
// The loop in Deflate should consume all avail_in
GOOGLE_LOG(DFATAL) << "Deflate left bytes unconsumed";
}
return true;
}
void GzipOutputStream::BackUp(int count) {
GOOGLE_CHECK_GE(zcontext_.avail_in, count);
zcontext_.avail_in -= count;
}
int64 GzipOutputStream::ByteCount() const {
return zcontext_.total_in + zcontext_.avail_in;
}
bool GzipOutputStream::Flush() {
zerror_ = Deflate(Z_FULL_FLUSH);
// Return true if the flush succeeded or if it was a no-op.
return (zerror_ == Z_OK) ||
(zerror_ == Z_BUF_ERROR && zcontext_.avail_in == 0 &&
zcontext_.avail_out != 0);
}
bool GzipOutputStream::Close() {
if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) {
return false;
}
do {
zerror_ = Deflate(Z_FINISH);
} while (zerror_ == Z_OK);
zerror_ = deflateEnd(&zcontext_);
bool ok = zerror_ == Z_OK;
zerror_ = Z_STREAM_END;
return ok;
}
} // namespace io
} // namespace protobuf
} // namespace google
#endif // HAVE_ZLIB
+209
View File
@@ -0,0 +1,209 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: brianolson@google.com (Brian Olson)
//
// This file contains the definition for classes GzipInputStream and
// GzipOutputStream.
//
// GzipInputStream decompresses data from an underlying
// ZeroCopyInputStream and provides the decompressed data as a
// ZeroCopyInputStream.
//
// GzipOutputStream is an ZeroCopyOutputStream that compresses data to
// an underlying ZeroCopyOutputStream.
#ifndef GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
#define GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <zlib.h>
namespace google {
namespace protobuf {
namespace io {
// A ZeroCopyInputStream that reads compressed data through zlib
class LIBPROTOBUF_EXPORT GzipInputStream : public ZeroCopyInputStream {
public:
// Format key for constructor
enum Format {
// zlib will autodetect gzip header or deflate stream
AUTO = 0,
// GZIP streams have some extra header data for file attributes.
GZIP = 1,
// Simpler zlib stream format.
ZLIB = 2,
};
// buffer_size and format may be -1 for default of 64kB and GZIP format
explicit GzipInputStream(
ZeroCopyInputStream* sub_stream,
Format format = AUTO,
int buffer_size = -1);
virtual ~GzipInputStream();
// Return last error message or NULL if no error.
inline const char* ZlibErrorMessage() const {
return zcontext_.msg;
}
inline int ZlibErrorCode() const {
return zerror_;
}
// implements ZeroCopyInputStream ----------------------------------
bool Next(const void** data, int* size);
void BackUp(int count);
bool Skip(int count);
int64 ByteCount() const;
private:
Format format_;
ZeroCopyInputStream* sub_stream_;
z_stream zcontext_;
int zerror_;
void* output_buffer_;
void* output_position_;
size_t output_buffer_length_;
int64 byte_count_;
int Inflate(int flush);
void DoNextOutput(const void** data, int* size);
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GzipInputStream);
};
class LIBPROTOBUF_EXPORT GzipOutputStream : public ZeroCopyOutputStream {
public:
// Format key for constructor
enum Format {
// GZIP streams have some extra header data for file attributes.
GZIP = 1,
// Simpler zlib stream format.
ZLIB = 2,
};
struct Options {
// Defaults to GZIP.
Format format;
// What size buffer to use internally. Defaults to 64kB.
int buffer_size;
// A number between 0 and 9, where 0 is no compression and 9 is best
// compression. Defaults to Z_DEFAULT_COMPRESSION (see zlib.h).
int compression_level;
// Defaults to Z_DEFAULT_STRATEGY. Can also be set to Z_FILTERED,
// Z_HUFFMAN_ONLY, or Z_RLE. See the documentation for deflateInit2 in
// zlib.h for definitions of these constants.
int compression_strategy;
Options(); // Initializes with default values.
};
// Create a GzipOutputStream with default options.
explicit GzipOutputStream(ZeroCopyOutputStream* sub_stream);
// Create a GzipOutputStream with the given options.
GzipOutputStream(
ZeroCopyOutputStream* sub_stream,
const Options& options);
virtual ~GzipOutputStream();
// Return last error message or NULL if no error.
inline const char* ZlibErrorMessage() const {
return zcontext_.msg;
}
inline int ZlibErrorCode() const {
return zerror_;
}
// Flushes data written so far to zipped data in the underlying stream.
// It is the caller's responsibility to flush the underlying stream if
// necessary.
// Compression may be less efficient stopping and starting around flushes.
// Returns true if no error.
//
// Please ensure that block size is > 6. Here is an excerpt from the zlib
// doc that explains why:
//
// In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out
// is greater than six to avoid repeated flush markers due to
// avail_out == 0 on return.
bool Flush();
// Writes out all data and closes the gzip stream.
// It is the caller's responsibility to close the underlying stream if
// necessary.
// Returns true if no error.
bool Close();
// implements ZeroCopyOutputStream ---------------------------------
bool Next(void** data, int* size);
void BackUp(int count);
int64 ByteCount() const;
private:
ZeroCopyOutputStream* sub_stream_;
// Result from calling Next() on sub_stream_
void* sub_data_;
int sub_data_size_;
z_stream zcontext_;
int zerror_;
void* input_buffer_;
size_t input_buffer_length_;
// Shared constructor code.
void Init(ZeroCopyOutputStream* sub_stream, const Options& options);
// Do some compression.
// Takes zlib flush mode.
// Returns zlib error code.
int Deflate(int flush);
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GzipOutputStream);
};
} // namespace io
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
@@ -37,6 +37,7 @@
// documentation generator.
namespace google {
namespace protobuf {
// Auxiliary classes used for I/O.
+372
View File
@@ -0,0 +1,372 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
namespace google {
namespace protobuf {
namespace io {
Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter)
: variable_delimiter_(variable_delimiter),
output_(output),
buffer_(NULL),
buffer_size_(0),
offset_(0),
at_start_of_line_(true),
failed_(false),
annotation_collector_(NULL) {}
Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter,
AnnotationCollector* annotation_collector)
: variable_delimiter_(variable_delimiter),
output_(output),
buffer_(NULL),
buffer_size_(0),
offset_(0),
at_start_of_line_(true),
failed_(false),
annotation_collector_(annotation_collector) {}
Printer::~Printer() {
// Only BackUp() if we have called Next() at least once and never failed.
if (buffer_size_ > 0 && !failed_) {
output_->BackUp(buffer_size_);
}
}
bool Printer::GetSubstitutionRange(const char* varname,
std::pair<size_t, size_t>* range) {
std::map<string, std::pair<size_t, size_t> >::const_iterator iter =
substitutions_.find(varname);
if (iter == substitutions_.end()) {
GOOGLE_LOG(DFATAL) << " Undefined variable in annotation: " << varname;
return false;
}
if (iter->second.first > iter->second.second) {
GOOGLE_LOG(DFATAL) << " Variable used for annotation used multiple times: "
<< varname;
return false;
}
*range = iter->second;
return true;
}
void Printer::Annotate(const char* begin_varname, const char* end_varname,
const string& file_path, const std::vector<int>& path) {
if (annotation_collector_ == NULL) {
// Can't generate signatures with this Printer.
return;
}
std::pair<size_t, size_t> begin, end;
if (!GetSubstitutionRange(begin_varname, &begin) ||
!GetSubstitutionRange(end_varname, &end)) {
return;
}
if (begin.first > end.second) {
GOOGLE_LOG(DFATAL) << " Annotation has negative length from " << begin_varname
<< " to " << end_varname;
} else {
annotation_collector_->AddAnnotation(begin.first, end.second, file_path,
path);
}
}
void Printer::Print(const std::map<string, string>& variables,
const char* text) {
int size = strlen(text);
int pos = 0; // The number of bytes we've written so far.
substitutions_.clear();
line_start_variables_.clear();
for (int i = 0; i < size; i++) {
if (text[i] == '\n') {
// Saw newline. If there is more text, we may need to insert an indent
// here. So, write what we have so far, including the '\n'.
WriteRaw(text + pos, i - pos + 1);
pos = i + 1;
// Setting this true will cause the next WriteRaw() to insert an indent
// first.
at_start_of_line_ = true;
line_start_variables_.clear();
} else if (text[i] == variable_delimiter_) {
// Saw the start of a variable name.
// Write what we have so far.
WriteRaw(text + pos, i - pos);
pos = i + 1;
// Find closing delimiter.
const char* end = strchr(text + pos, variable_delimiter_);
if (end == NULL) {
GOOGLE_LOG(DFATAL) << " Unclosed variable name.";
end = text + pos;
}
int endpos = end - text;
string varname(text + pos, endpos - pos);
if (varname.empty()) {
// Two delimiters in a row reduce to a literal delimiter character.
WriteRaw(&variable_delimiter_, 1);
} else {
// Replace with the variable's value.
std::map<string, string>::const_iterator iter = variables.find(varname);
if (iter == variables.end()) {
GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname;
} else {
if (at_start_of_line_ && iter->second.empty()) {
line_start_variables_.push_back(varname);
}
WriteRaw(iter->second.data(), iter->second.size());
std::pair<std::map<string, std::pair<size_t, size_t> >::iterator,
bool>
inserted = substitutions_.insert(std::make_pair(
varname,
std::make_pair(offset_ - iter->second.size(), offset_)));
if (!inserted.second) {
// This variable was used multiple times. Make its span have
// negative length so we can detect it if it gets used in an
// annotation.
inserted.first->second = std::make_pair(1, 0);
}
}
}
// Advance past this variable.
i = endpos;
pos = endpos + 1;
}
}
// Write the rest.
WriteRaw(text + pos, size - pos);
}
void Printer::Print(const char* text) {
static std::map<string, string> empty;
Print(empty, text);
}
void Printer::Print(const char* text,
const char* variable, const string& value) {
std::map<string, string> vars;
vars[variable] = value;
Print(vars, text);
}
void Printer::Print(const char* text,
const char* variable1, const string& value1,
const char* variable2, const string& value2) {
std::map<string, string> vars;
vars[variable1] = value1;
vars[variable2] = value2;
Print(vars, text);
}
void Printer::Print(const char* text,
const char* variable1, const string& value1,
const char* variable2, const string& value2,
const char* variable3, const string& value3) {
std::map<string, string> vars;
vars[variable1] = value1;
vars[variable2] = value2;
vars[variable3] = value3;
Print(vars, text);
}
void Printer::Print(const char* text,
const char* variable1, const string& value1,
const char* variable2, const string& value2,
const char* variable3, const string& value3,
const char* variable4, const string& value4) {
std::map<string, string> vars;
vars[variable1] = value1;
vars[variable2] = value2;
vars[variable3] = value3;
vars[variable4] = value4;
Print(vars, text);
}
void Printer::Print(const char* text,
const char* variable1, const string& value1,
const char* variable2, const string& value2,
const char* variable3, const string& value3,
const char* variable4, const string& value4,
const char* variable5, const string& value5) {
std::map<string, string> vars;
vars[variable1] = value1;
vars[variable2] = value2;
vars[variable3] = value3;
vars[variable4] = value4;
vars[variable5] = value5;
Print(vars, text);
}
void Printer::Print(const char* text,
const char* variable1, const string& value1,
const char* variable2, const string& value2,
const char* variable3, const string& value3,
const char* variable4, const string& value4,
const char* variable5, const string& value5,
const char* variable6, const string& value6) {
std::map<string, string> vars;
vars[variable1] = value1;
vars[variable2] = value2;
vars[variable3] = value3;
vars[variable4] = value4;
vars[variable5] = value5;
vars[variable6] = value6;
Print(vars, text);
}
void Printer::Print(const char* text,
const char* variable1, const string& value1,
const char* variable2, const string& value2,
const char* variable3, const string& value3,
const char* variable4, const string& value4,
const char* variable5, const string& value5,
const char* variable6, const string& value6,
const char* variable7, const string& value7) {
std::map<string, string> vars;
vars[variable1] = value1;
vars[variable2] = value2;
vars[variable3] = value3;
vars[variable4] = value4;
vars[variable5] = value5;
vars[variable6] = value6;
vars[variable7] = value7;
Print(vars, text);
}
void Printer::Print(const char* text,
const char* variable1, const string& value1,
const char* variable2, const string& value2,
const char* variable3, const string& value3,
const char* variable4, const string& value4,
const char* variable5, const string& value5,
const char* variable6, const string& value6,
const char* variable7, const string& value7,
const char* variable8, const string& value8) {
std::map<string, string> vars;
vars[variable1] = value1;
vars[variable2] = value2;
vars[variable3] = value3;
vars[variable4] = value4;
vars[variable5] = value5;
vars[variable6] = value6;
vars[variable7] = value7;
vars[variable8] = value8;
Print(vars, text);
}
void Printer::Indent() {
indent_ += " ";
}
void Printer::Outdent() {
if (indent_.empty()) {
GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
return;
}
indent_.resize(indent_.size() - 2);
}
void Printer::PrintRaw(const string& data) {
WriteRaw(data.data(), data.size());
}
void Printer::PrintRaw(const char* data) {
if (failed_) return;
WriteRaw(data, strlen(data));
}
void Printer::WriteRaw(const char* data, int size) {
if (failed_) return;
if (size == 0) return;
if (at_start_of_line_ && (size > 0) && (data[0] != '\n')) {
// Insert an indent.
at_start_of_line_ = false;
CopyToBuffer(indent_.data(), indent_.size());
if (failed_) return;
// Fix up empty variables (e.g., "{") that should be annotated as
// coming after the indent.
for (std::vector<string>::iterator i = line_start_variables_.begin();
i != line_start_variables_.end(); ++i) {
substitutions_[*i].first += indent_.size();
substitutions_[*i].second += indent_.size();
}
}
// If we're going to write any data, clear line_start_variables_, since
// we've either updated them in the block above or they no longer refer to
// the current line.
line_start_variables_.clear();
CopyToBuffer(data, size);
}
void Printer::CopyToBuffer(const char* data, int size) {
if (failed_) return;
if (size == 0) return;
while (size > buffer_size_) {
// Data exceeds space in the buffer. Copy what we can and request a
// new buffer.
memcpy(buffer_, data, buffer_size_);
offset_ += buffer_size_;
data += buffer_size_;
size -= buffer_size_;
void* void_buffer;
failed_ = !output_->Next(&void_buffer, &buffer_size_);
if (failed_) return;
buffer_ = reinterpret_cast<char*>(void_buffer);
}
// Buffer is big enough to receive the data; copy it.
memcpy(buffer_, data, size);
buffer_ += size;
buffer_size_ -= size;
offset_ += size;
}
} // namespace io
} // namespace protobuf
} // namespace google
+363
View File
@@ -0,0 +1,363 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
//
// Utility class for writing text to a ZeroCopyOutputStream.
#ifndef GOOGLE_PROTOBUF_IO_PRINTER_H__
#define GOOGLE_PROTOBUF_IO_PRINTER_H__
#include <string>
#include <map>
#include <vector>
#include <google/protobuf/stubs/common.h>
namespace google {
namespace protobuf {
namespace io {
class ZeroCopyOutputStream; // zero_copy_stream.h
// Records annotations about a Printer's output.
class LIBPROTOBUF_EXPORT AnnotationCollector {
public:
// Records that the bytes in file_path beginning with begin_offset and ending
// before end_offset are associated with the SourceCodeInfo-style path.
virtual void AddAnnotation(size_t begin_offset, size_t end_offset,
const string& file_path,
const std::vector<int>& path) = 0;
virtual ~AnnotationCollector() {}
};
// Records annotations about a Printer's output to the given protocol buffer,
// assuming that the buffer has an ::Annotation message exposing path,
// source_file, begin and end fields.
template <typename AnnotationProto>
class AnnotationProtoCollector : public AnnotationCollector {
public:
// annotation_proto is the protocol buffer to which new Annotations should be
// added. It is not owned by the AnnotationProtoCollector.
explicit AnnotationProtoCollector(AnnotationProto* annotation_proto)
: annotation_proto_(annotation_proto) {}
// Override for AnnotationCollector::AddAnnotation.
virtual void AddAnnotation(size_t begin_offset, size_t end_offset,
const string& file_path,
const std::vector<int>& path) {
typename AnnotationProto::Annotation* annotation =
annotation_proto_->add_annotation();
for (int i = 0; i < path.size(); ++i) {
annotation->add_path(path[i]);
}
annotation->set_source_file(file_path);
annotation->set_begin(begin_offset);
annotation->set_end(end_offset);
}
private:
// The protocol buffer to which new annotations should be added.
AnnotationProto* const annotation_proto_;
};
// This simple utility class assists in code generation. It basically
// allows the caller to define a set of variables and then output some
// text with variable substitutions. Example usage:
//
// Printer printer(output, '$');
// map<string, string> vars;
// vars["name"] = "Bob";
// printer.Print(vars, "My name is $name$.");
//
// The above writes "My name is Bob." to the output stream.
//
// Printer aggressively enforces correct usage, crashing (with assert failures)
// in the case of undefined variables in debug builds. This helps greatly in
// debugging code which uses it.
//
// If a Printer is constructed with an AnnotationCollector, it will provide it
// with annotations that connect the Printer's output to paths that can identify
// various descriptors. In the above example, if person_ is a descriptor that
// identifies Bob, we can associate the output string "My name is Bob." with
// a source path pointing to that descriptor with:
//
// printer.Annotate("name", person_);
//
// The AnnotationCollector will be sent an annotation linking the output range
// covering "Bob" to the logical path provided by person_. Tools may use
// this association to (for example) link "Bob" in the output back to the
// source file that defined the person_ descriptor identifying Bob.
//
// Annotate can only examine variables substituted during the last call to
// Print. It is invalid to refer to a variable that was used multiple times
// in a single Print call.
//
// In full generality, one may specify a range of output text using a beginning
// substitution variable and an ending variable. The resulting annotation will
// span from the first character of the substituted value for the beginning
// variable to the last character of the substituted value for the ending
// variable. For example, the Annotate call above is equivalent to this one:
//
// printer.Annotate("name", "name", person_);
//
// This is useful if multiple variables combine to form a single span of output
// that should be annotated with the same source path. For example:
//
// Printer printer(output, '$');
// map<string, string> vars;
// vars["first"] = "Alice";
// vars["last"] = "Smith";
// printer.Print(vars, "My name is $first$ $last$.");
// printer.Annotate("first", "last", person_);
//
// This code would associate the span covering "Alice Smith" in the output with
// the person_ descriptor.
//
// Note that the beginning variable must come before (or overlap with, in the
// case of zero-sized substitution values) the ending variable.
//
// It is also sometimes useful to use variables with zero-sized values as
// markers. This avoids issues with multiple references to the same variable
// and also allows annotation ranges to span literal text from the Print
// templates:
//
// Printer printer(output, '$');
// map<string, string> vars;
// vars["foo"] = "bar";
// vars["function"] = "call";
// vars["mark"] = "";
// printer.Print(vars, "$function$($foo$,$foo$)$mark$");
// printer.Annotate("function", "mark", call_);
//
// This code associates the span covering "call(bar,bar)" in the output with the
// call_ descriptor.
class LIBPROTOBUF_EXPORT Printer {
public:
// Create a printer that writes text to the given output stream. Use the
// given character as the delimiter for variables.
Printer(ZeroCopyOutputStream* output, char variable_delimiter);
// Create a printer that writes text to the given output stream. Use the
// given character as the delimiter for variables. If annotation_collector
// is not null, Printer will provide it with annotations about code written
// to the stream. annotation_collector is not owned by Printer.
Printer(ZeroCopyOutputStream* output, char variable_delimiter,
AnnotationCollector* annotation_collector);
~Printer();
// Link a subsitution variable emitted by the last call to Print to the object
// described by descriptor.
template <typename SomeDescriptor>
void Annotate(const char* varname, const SomeDescriptor* descriptor) {
Annotate(varname, varname, descriptor);
}
// Link the output range defined by the substitution variables as emitted by
// the last call to Print to the object described by descriptor. The range
// begins at begin_varname's value and ends after the last character of the
// value substituted for end_varname.
template <typename SomeDescriptor>
void Annotate(const char* begin_varname, const char* end_varname,
const SomeDescriptor* descriptor) {
if (annotation_collector_ == NULL) {
// Annotations aren't turned on for this Printer, so don't pay the cost
// of building the location path.
return;
}
std::vector<int> path;
descriptor->GetLocationPath(&path);
Annotate(begin_varname, end_varname, descriptor->file()->name(), path);
}
// Link a subsitution variable emitted by the last call to Print to the file
// with path file_name.
void Annotate(const char* varname, const string& file_name) {
Annotate(varname, varname, file_name);
}
// Link the output range defined by the substitution variables as emitted by
// the last call to Print to the file with path file_name. The range begins
// at begin_varname's value and ends after the last character of the value
// substituted for end_varname.
void Annotate(const char* begin_varname, const char* end_varname,
const string& file_name) {
if (annotation_collector_ == NULL) {
// Annotations aren't turned on for this Printer.
return;
}
std::vector<int> empty_path;
Annotate(begin_varname, end_varname, file_name, empty_path);
}
// Print some text after applying variable substitutions. If a particular
// variable in the text is not defined, this will crash. Variables to be
// substituted are identified by their names surrounded by delimiter
// characters (as given to the constructor). The variable bindings are
// defined by the given map.
void Print(const std::map<string, string>& variables, const char* text);
// Like the first Print(), except the substitutions are given as parameters.
void Print(const char* text);
// Like the first Print(), except the substitutions are given as parameters.
void Print(const char* text, const char* variable, const string& value);
// Like the first Print(), except the substitutions are given as parameters.
void Print(const char* text, const char* variable1, const string& value1,
const char* variable2, const string& value2);
// Like the first Print(), except the substitutions are given as parameters.
void Print(const char* text, const char* variable1, const string& value1,
const char* variable2, const string& value2,
const char* variable3, const string& value3);
// Like the first Print(), except the substitutions are given as parameters.
void Print(const char* text, const char* variable1, const string& value1,
const char* variable2, const string& value2,
const char* variable3, const string& value3,
const char* variable4, const string& value4);
// Like the first Print(), except the substitutions are given as parameters.
void Print(const char* text, const char* variable1, const string& value1,
const char* variable2, const string& value2,
const char* variable3, const string& value3,
const char* variable4, const string& value4,
const char* variable5, const string& value5);
// Like the first Print(), except the substitutions are given as parameters.
void Print(const char* text, const char* variable1, const string& value1,
const char* variable2, const string& value2,
const char* variable3, const string& value3,
const char* variable4, const string& value4,
const char* variable5, const string& value5,
const char* variable6, const string& value6);
// Like the first Print(), except the substitutions are given as parameters.
void Print(const char* text, const char* variable1, const string& value1,
const char* variable2, const string& value2,
const char* variable3, const string& value3,
const char* variable4, const string& value4,
const char* variable5, const string& value5,
const char* variable6, const string& value6,
const char* variable7, const string& value7);
// Like the first Print(), except the substitutions are given as parameters.
void Print(const char* text, const char* variable1, const string& value1,
const char* variable2, const string& value2,
const char* variable3, const string& value3,
const char* variable4, const string& value4,
const char* variable5, const string& value5,
const char* variable6, const string& value6,
const char* variable7, const string& value7,
const char* variable8, const string& value8);
// Indent text by two spaces. After calling Indent(), two spaces will be
// inserted at the beginning of each line of text. Indent() may be called
// multiple times to produce deeper indents.
void Indent();
// Reduces the current indent level by two spaces, or crashes if the indent
// level is zero.
void Outdent();
// Write a string to the output buffer.
// This method does not look for newlines to add indentation.
void PrintRaw(const string& data);
// Write a zero-delimited string to output buffer.
// This method does not look for newlines to add indentation.
void PrintRaw(const char* data);
// Write some bytes to the output buffer.
// This method does not look for newlines to add indentation.
void WriteRaw(const char* data, int size);
// True if any write to the underlying stream failed. (We don't just
// crash in this case because this is an I/O failure, not a programming
// error.)
bool failed() const { return failed_; }
private:
// Link the output range defined by the substitution variables as emitted by
// the last call to Print to the object found at the SourceCodeInfo-style path
// in a file with path file_path. The range begins at the start of
// begin_varname's value and ends after the last character of the value
// substituted for end_varname. Note that begin_varname and end_varname
// may refer to the same variable.
void Annotate(const char* begin_varname, const char* end_varname,
const string& file_path, const std::vector<int>& path);
// Copy size worth of bytes from data to buffer_.
void CopyToBuffer(const char* data, int size);
const char variable_delimiter_;
ZeroCopyOutputStream* const output_;
char* buffer_;
int buffer_size_;
// The current position, in bytes, in the output stream. This is equivalent
// to the total number of bytes that have been written so far. This value is
// used to calculate annotation ranges in the substitutions_ map below.
size_t offset_;
string indent_;
bool at_start_of_line_;
bool failed_;
// A map from variable name to [start, end) offsets in the output buffer.
// These refer to the offsets used for a variable after the last call to
// Print. If a variable was used more than once, the entry used in
// this map is set to a negative-length span. For singly-used variables, the
// start offset is the beginning of the substitution; the end offset is the
// last byte of the substitution plus one (such that (end - start) is the
// length of the substituted string).
std::map<string, std::pair<size_t, size_t> > substitutions_;
// Keeps track of the keys in substitutions_ that need to be updated when
// indents are inserted. These are keys that refer to the beginning of the
// current line.
std::vector<string> line_start_variables_;
// Returns true and sets range to the substitution range in the output for
// varname if varname was used once in the last call to Print. If varname
// was not used, or if it was used multiple times, returns false (and
// fails a debug assertion).
bool GetSubstitutionRange(const char* varname,
std::pair<size_t, size_t>* range);
// If non-null, annotation_collector_ is used to store annotations about
// generated code.
AnnotationCollector* const annotation_collector_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Printer);
};
} // namespace io
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_IO_PRINTER_H__
+67 -24
View File
@@ -38,45 +38,88 @@
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
namespace io {
// This approximately 0x1.ffffffp127, but we don't use 0x1.ffffffp127 because
// it won't compile in MSVC.
const double MAX_FLOAT_AS_DOUBLE_ROUNDED = 3.4028235677973366e+38;
// ----------------------------------------------------------------------
// NoLocaleStrtod()
// This code will make you cry.
// ----------------------------------------------------------------------
namespace {
// Returns a string identical to *input except that the character pointed to
// by radix_pos (which should be '.') is replaced with the locale-specific
// radix character.
string LocalizeRadix(const char* input, const char* radix_pos) {
// Determine the locale-specific radix character by calling sprintf() to
// print the number 1.5, then stripping off the digits. As far as I can
// tell, this is the only portable, thread-safe way to get the C library
// to divuldge the locale's radix character. No, localeconv() is NOT
// thread-safe.
char temp[16];
int size = sprintf(temp, "%.1f", 1.5);
GOOGLE_CHECK_EQ(temp[0], '1');
GOOGLE_CHECK_EQ(temp[size-1], '5');
GOOGLE_CHECK_LE(size, 6);
// Now replace the '.' in the input with it.
string result;
result.reserve(strlen(input) + size - 3);
result.append(input, radix_pos);
result.append(temp + 1, size - 2);
result.append(radix_pos + 1);
return result;
}
} // namespace
double NoLocaleStrtod(const char* text, char** original_endptr) {
// We cannot simply set the locale to "C" temporarily with setlocale()
// as this is not thread-safe. Instead, we try to parse in the current
// locale first. If parsing stops at a '.' character, then this is a
// pretty good hint that we're actually in some other locale in which
// '.' is not the radix character.
char* temp_endptr;
double result = strtod(text, &temp_endptr);
if (original_endptr != NULL) *original_endptr = temp_endptr;
if (*temp_endptr != '.') return result;
// Parsing halted on a '.'. Perhaps we're in a different locale? Let's
// try to replace the '.' with a locale-specific radix character and
// try again.
string localized = LocalizeRadix(text, temp_endptr);
const char* localized_cstr = localized.c_str();
char* localized_endptr;
result = strtod(localized_cstr, &localized_endptr);
if ((localized_endptr - localized_cstr) >
(temp_endptr - text)) {
// This attempt got further, so replacing the decimal must have helped.
// Update original_endptr to point at the right location.
if (original_endptr != NULL) {
// size_diff is non-zero if the localized radix has multiple bytes.
int size_diff = localized.size() - strlen(text);
// const_cast is necessary to match the strtod() interface.
*original_endptr = const_cast<char*>(
text + (localized_endptr - localized_cstr - size_diff));
}
}
return result;
}
float SafeDoubleToFloat(double value) {
// static_cast<float> on a number larger than float can result in illegal
// instruction error, so we need to manually convert it to infinity or max.
if (value > std::numeric_limits<float>::max()) {
// Max float value is about 3.4028234664E38 when represented as a double.
// However, when printing float as text, it will be rounded as
// 3.4028235e+38. If we parse the value of 3.4028235e+38 from text and
// compare it to 3.4028234664E38, we may think that it is larger, but
// actually, any number between these two numbers could only be represented
// as the same max float number in float, so we should treat them the same
// as max float.
if (value <= MAX_FLOAT_AS_DOUBLE_ROUNDED) {
return std::numeric_limits<float>::max();
}
return std::numeric_limits<float>::infinity();
} else if (value < -std::numeric_limits<float>::max()) {
if (value >= -MAX_FLOAT_AS_DOUBLE_ROUNDED) {
return -std::numeric_limits<float>::max();
}
return -std::numeric_limits<float>::infinity();
} else {
return static_cast<float>(value);
}
}
double NoLocaleStrtod(const char* str, char** endptr) {
return google::protobuf::internal::NoLocaleStrtod(str, endptr);
}
} // namespace io
} // namespace protobuf
} // namespace google
+1 -1
View File
@@ -50,6 +50,6 @@ float SafeDoubleToFloat(double value);
} // namespace io
} // namespace protobuf
} // namespace google
} // namespace google
#endif // GOOGLE_PROTOBUF_IO_STRTOD_H__
+164 -210
View File
@@ -89,13 +89,12 @@
// exactly pretty.
#include <google/protobuf/io/tokenizer.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/stringprintf.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/io/strtod.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/stl_util.h>
namespace google {
@@ -114,34 +113,39 @@ namespace {
// Note: No class is allowed to contain '\0', since this is used to mark end-
// of-input and is handled specially.
#define CHARACTER_CLASS(NAME, EXPRESSION) \
class NAME { \
public: \
static inline bool InClass(char c) { return EXPRESSION; } \
#define CHARACTER_CLASS(NAME, EXPRESSION) \
class NAME { \
public: \
static inline bool InClass(char c) { \
return EXPRESSION; \
} \
}
CHARACTER_CLASS(Whitespace, c == ' ' || c == '\n' || c == '\t' || c == '\r' ||
c == '\v' || c == '\f');
CHARACTER_CLASS(WhitespaceNoNewline,
c == ' ' || c == '\t' || c == '\r' || c == '\v' || c == '\f');
CHARACTER_CLASS(Whitespace, c == ' ' || c == '\n' || c == '\t' ||
c == '\r' || c == '\v' || c == '\f');
CHARACTER_CLASS(WhitespaceNoNewline, c == ' ' || c == '\t' ||
c == '\r' || c == '\v' || c == '\f');
CHARACTER_CLASS(Unprintable, c<' ' && c> '\0');
CHARACTER_CLASS(Unprintable, c < ' ' && c > '\0');
CHARACTER_CLASS(Digit, '0' <= c && c <= '9');
CHARACTER_CLASS(OctalDigit, '0' <= c && c <= '7');
CHARACTER_CLASS(HexDigit, ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') ||
('A' <= c && c <= 'F'));
CHARACTER_CLASS(HexDigit, ('0' <= c && c <= '9') ||
('a' <= c && c <= 'f') ||
('A' <= c && c <= 'F'));
CHARACTER_CLASS(Letter,
('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || (c == '_'));
CHARACTER_CLASS(Letter, ('a' <= c && c <= 'z') ||
('A' <= c && c <= 'Z') ||
(c == '_'));
CHARACTER_CLASS(Alphanumeric, ('a' <= c && c <= 'z') ||
('A' <= c && c <= 'Z') ||
('0' <= c && c <= '9') || (c == '_'));
('A' <= c && c <= 'Z') ||
('0' <= c && c <= '9') ||
(c == '_'));
CHARACTER_CLASS(Escape, c == 'a' || c == 'b' || c == 'f' || c == 'n' ||
c == 'r' || c == 't' || c == 'v' || c == '\\' ||
c == '?' || c == '\'' || c == '\"');
c == 'r' || c == 't' || c == 'v' || c == '\\' ||
c == '?' || c == '\'' || c == '\"');
#undef CHARACTER_CLASS
@@ -157,32 +161,20 @@ inline int DigitValue(char digit) {
// Inline because it's only used in one place.
inline char TranslateEscape(char c) {
switch (c) {
case 'a':
return '\a';
case 'b':
return '\b';
case 'f':
return '\f';
case 'n':
return '\n';
case 'r':
return '\r';
case 't':
return '\t';
case 'v':
return '\v';
case '\\':
return '\\';
case '?':
return '\?'; // Trigraphs = :(
case '\'':
return '\'';
case '"':
return '\"';
case 'a': return '\a';
case 'b': return '\b';
case 'f': return '\f';
case 'n': return '\n';
case 'r': return '\r';
case 't': return '\t';
case 'v': return '\v';
case '\\': return '\\';
case '?': return '\?'; // Trigraphs = :(
case '\'': return '\'';
case '"': return '\"';
// We expect escape sequences to have been validated separately.
default:
return '?';
default: return '?';
}
}
@@ -194,20 +186,21 @@ ErrorCollector::~ErrorCollector() {}
Tokenizer::Tokenizer(ZeroCopyInputStream* input,
ErrorCollector* error_collector)
: input_(input),
error_collector_(error_collector),
buffer_(NULL),
buffer_size_(0),
buffer_pos_(0),
read_error_(false),
line_(0),
column_(0),
record_target_(NULL),
record_start_(-1),
allow_f_after_float_(false),
comment_style_(CPP_COMMENT_STYLE),
require_space_after_number_(true),
allow_multiline_strings_(false) {
: input_(input),
error_collector_(error_collector),
buffer_(NULL),
buffer_size_(0),
buffer_pos_(0),
read_error_(false),
line_(0),
column_(0),
record_target_(NULL),
record_start_(-1),
allow_f_after_float_(false),
comment_style_(CPP_COMMENT_STYLE),
require_space_after_number_(true),
allow_multiline_strings_(false) {
current_.line = 0;
current_.column = 0;
current_.end_column = 0;
@@ -224,21 +217,6 @@ Tokenizer::~Tokenizer() {
}
}
bool Tokenizer::report_whitespace() const { return report_whitespace_; }
// Note: `set_report_whitespace(false)` implies `set_report_newlines(false)`.
void Tokenizer::set_report_whitespace(bool report) {
report_whitespace_ = report;
report_newlines_ &= report;
}
// If true, newline tokens are reported by Next().
bool Tokenizer::report_newlines() const { return report_newlines_; }
// Note: `set_report_newlines(true)` implies `set_report_whitespace(true)`.
void Tokenizer::set_report_newlines(bool report) {
report_newlines_ = report;
report_whitespace_ |= report; // enable report_whitespace if necessary
}
// -------------------------------------------------------------------
// Internal helpers.
@@ -271,8 +249,7 @@ void Tokenizer::Refresh() {
// If we're in a token, append the rest of the buffer to it.
if (record_target_ != NULL && record_start_ < buffer_size_) {
record_target_->append(buffer_ + record_start_,
buffer_size_ - record_start_);
record_target_->append(buffer_ + record_start_, buffer_size_ - record_start_);
record_start_ = 0;
}
@@ -294,7 +271,7 @@ void Tokenizer::Refresh() {
current_char_ = buffer_[0];
}
inline void Tokenizer::RecordTo(std::string* target) {
inline void Tokenizer::RecordTo(string* target) {
record_target_ = target;
record_start_ = buffer_pos_;
}
@@ -305,15 +282,14 @@ inline void Tokenizer::StopRecording() {
// be helpful by detecting the NULL pointer, even though there's nothing
// wrong with reading zero bytes from NULL.
if (buffer_pos_ != record_start_) {
record_target_->append(buffer_ + record_start_,
buffer_pos_ - record_start_);
record_target_->append(buffer_ + record_start_, buffer_pos_ - record_start_);
}
record_target_ = NULL;
record_start_ = -1;
}
inline void Tokenizer::StartToken() {
current_.type = TYPE_START; // Just for the sake of initializing it.
current_.type = TYPE_START; // Just for the sake of initializing it.
current_.text.clear();
current_.line = line_;
current_.column = column_;
@@ -328,12 +304,12 @@ inline void Tokenizer::EndToken() {
// -------------------------------------------------------------------
// Helper methods that consume characters.
template <typename CharacterClass>
template<typename CharacterClass>
inline bool Tokenizer::LookingAt() {
return CharacterClass::InClass(current_char_);
}
template <typename CharacterClass>
template<typename CharacterClass>
inline bool Tokenizer::TryConsumeOne() {
if (CharacterClass::InClass(current_char_)) {
NextChar();
@@ -352,14 +328,14 @@ inline bool Tokenizer::TryConsume(char c) {
}
}
template <typename CharacterClass>
template<typename CharacterClass>
inline void Tokenizer::ConsumeZeroOrMore() {
while (CharacterClass::InClass(current_char_)) {
NextChar();
}
}
template <typename CharacterClass>
template<typename CharacterClass>
inline void Tokenizer::ConsumeOneOrMore(const char* error) {
if (!CharacterClass::InClass(current_char_)) {
AddError(error);
@@ -405,21 +381,25 @@ void Tokenizer::ConsumeString(char delimiter) {
}
// Possibly followed by another hex digit, but again we don't care.
} else if (TryConsume('u')) {
if (!TryConsumeOne<HexDigit>() || !TryConsumeOne<HexDigit>() ||
!TryConsumeOne<HexDigit>() || !TryConsumeOne<HexDigit>()) {
if (!TryConsumeOne<HexDigit>() ||
!TryConsumeOne<HexDigit>() ||
!TryConsumeOne<HexDigit>() ||
!TryConsumeOne<HexDigit>()) {
AddError("Expected four hex digits for \\u escape sequence.");
}
} else if (TryConsume('U')) {
// We expect 8 hex digits; but only the range up to 0x10ffff is
// legal.
if (!TryConsume('0') || !TryConsume('0') ||
if (!TryConsume('0') ||
!TryConsume('0') ||
!(TryConsume('0') || TryConsume('1')) ||
!TryConsumeOne<HexDigit>() || !TryConsumeOne<HexDigit>() ||
!TryConsumeOne<HexDigit>() || !TryConsumeOne<HexDigit>() ||
!TryConsumeOne<HexDigit>() ||
!TryConsumeOne<HexDigit>() ||
!TryConsumeOne<HexDigit>() ||
!TryConsumeOne<HexDigit>() ||
!TryConsumeOne<HexDigit>()) {
AddError(
"Expected eight hex digits up to 10ffff for \\U escape "
"sequence");
AddError("Expected eight hex digits up to 10ffff for \\U escape "
"sequence");
}
} else {
AddError("Invalid escape sequence in string literal.");
@@ -485,7 +465,7 @@ Tokenizer::TokenType Tokenizer::ConsumeNumber(bool started_with_zero,
} else if (current_char_ == '.') {
if (is_float) {
AddError(
"Already saw decimal point or exponent; can't have another one.");
"Already saw decimal point or exponent; can't have another one.");
} else {
AddError("Hex and octal numbers must be integers.");
}
@@ -494,7 +474,7 @@ Tokenizer::TokenType Tokenizer::ConsumeNumber(bool started_with_zero,
return is_float ? TYPE_FLOAT : TYPE_INTEGER;
}
void Tokenizer::ConsumeLineComment(std::string* content) {
void Tokenizer::ConsumeLineComment(string* content) {
if (content != NULL) RecordTo(content);
while (current_char_ != '\0' && current_char_ != '\n') {
@@ -505,15 +485,17 @@ void Tokenizer::ConsumeLineComment(std::string* content) {
if (content != NULL) StopRecording();
}
void Tokenizer::ConsumeBlockComment(std::string* content) {
void Tokenizer::ConsumeBlockComment(string* content) {
int start_line = line_;
int start_column = column_ - 2;
if (content != NULL) RecordTo(content);
while (true) {
while (current_char_ != '\0' && current_char_ != '*' &&
current_char_ != '/' && current_char_ != '\n') {
while (current_char_ != '\0' &&
current_char_ != '*' &&
current_char_ != '/' &&
current_char_ != '\n') {
NextChar();
}
@@ -542,11 +524,11 @@ void Tokenizer::ConsumeBlockComment(std::string* content) {
// Note: We didn't consume the '*' because if there is a '/' after it
// we want to interpret that as the end of the comment.
AddError(
"\"/*\" inside block comment. Block comments cannot be nested.");
"\"/*\" inside block comment. Block comments cannot be nested.");
} else if (current_char_ == '\0') {
AddError("End-of-file inside block comment.");
error_collector_->AddError(start_line, start_column,
" Comment started here.");
error_collector_->AddError(
start_line, start_column, " Comment started here.");
if (content != NULL) StopRecording();
break;
}
@@ -575,46 +557,13 @@ Tokenizer::NextCommentStatus Tokenizer::TryConsumeCommentStart() {
}
}
bool Tokenizer::TryConsumeWhitespace() {
if (report_newlines_) {
if (TryConsumeOne<WhitespaceNoNewline>()) {
ConsumeZeroOrMore<WhitespaceNoNewline>();
current_.type = TYPE_WHITESPACE;
return true;
}
return false;
}
if (TryConsumeOne<Whitespace>()) {
ConsumeZeroOrMore<Whitespace>();
current_.type = TYPE_WHITESPACE;
return report_whitespace_;
}
return false;
}
bool Tokenizer::TryConsumeNewline() {
if (!report_whitespace_ || !report_newlines_) {
return false;
}
if (TryConsume('\n')) {
current_.type = TYPE_NEWLINE;
return true;
}
return false;
}
// -------------------------------------------------------------------
bool Tokenizer::Next() {
previous_ = current_;
while (!read_error_) {
StartToken();
bool report_token = TryConsumeWhitespace() || TryConsumeNewline();
EndToken();
if (report_token) {
return true;
}
ConsumeZeroOrMore<Whitespace>();
switch (TryConsumeCommentStart()) {
case LINE_COMMENT:
@@ -664,9 +613,8 @@ bool Tokenizer::Next() {
current_.line == previous_.line &&
current_.column == previous_.end_column) {
// We don't accept syntax like "blah.123".
error_collector_->AddError(
line_, column_ - 2,
"Need space between identifier and decimal point.");
error_collector_->AddError(line_, column_ - 2,
"Need space between identifier and decimal point.");
}
current_.type = ConsumeNumber(false, true);
} else {
@@ -683,8 +631,7 @@ bool Tokenizer::Next() {
} else {
// Check if the high order bit is set.
if (current_char_ & 0x80) {
error_collector_->AddError(
line_, column_,
error_collector_->AddError(line_, column_,
StringPrintf("Interpreting non ascii codepoint %d.",
static_cast<unsigned char>(current_char_)));
}
@@ -717,9 +664,9 @@ namespace {
// next_leading_comments.
class CommentCollector {
public:
CommentCollector(std::string* prev_trailing_comments,
std::vector<std::string>* detached_comments,
std::string* next_leading_comments)
CommentCollector(string* prev_trailing_comments,
std::vector<string>* detached_comments,
string* next_leading_comments)
: prev_trailing_comments_(prev_trailing_comments),
detached_comments_(detached_comments),
next_leading_comments_(next_leading_comments),
@@ -740,7 +687,7 @@ class CommentCollector {
// About to read a line comment. Get the comment buffer pointer in order to
// read into it.
std::string* GetBufferForLineComment() {
string* GetBufferForLineComment() {
// We want to combine with previous line comments, but not block comments.
if (has_comment_ && !is_line_comment_) {
Flush();
@@ -752,7 +699,7 @@ class CommentCollector {
// About to read a block comment. Get the comment buffer pointer in order to
// read into it.
std::string* GetBufferForBlockComment() {
string* GetBufferForBlockComment() {
if (has_comment_) {
Flush();
}
@@ -784,14 +731,16 @@ class CommentCollector {
}
}
void DetachFromPrev() { can_attach_to_prev_ = false; }
void DetachFromPrev() {
can_attach_to_prev_ = false;
}
private:
std::string* prev_trailing_comments_;
std::vector<std::string>* detached_comments_;
std::string* next_leading_comments_;
string* prev_trailing_comments_;
std::vector<string>* detached_comments_;
string* next_leading_comments_;
std::string comment_buffer_;
string comment_buffer_;
// True if any comments were read into comment_buffer_. This can be true even
// if comment_buffer_ is empty, namely if the comment was "/**/".
@@ -805,23 +754,21 @@ class CommentCollector {
bool can_attach_to_prev_;
};
} // namespace
} // namespace
bool Tokenizer::NextWithComments(std::string* prev_trailing_comments,
std::vector<std::string>* detached_comments,
std::string* next_leading_comments) {
bool Tokenizer::NextWithComments(string* prev_trailing_comments,
std::vector<string>* detached_comments,
string* next_leading_comments) {
CommentCollector collector(prev_trailing_comments, detached_comments,
next_leading_comments);
if (current_.type == TYPE_START) {
// Ignore unicode byte order mark(BOM) if it appears at the file
// beginning. Only UTF-8 BOM (0xEF 0xBB 0xBF) is accepted.
if (TryConsume(static_cast<char>(0xEF))) {
if (!TryConsume(static_cast<char>(0xBB)) ||
!TryConsume(static_cast<char>(0xBF))) {
AddError(
"Proto file starts with 0xEF but not UTF-8 BOM. "
"Only UTF-8 is accepted for proto file.");
if (TryConsume((char)0xEF)) {
if (!TryConsume((char)0xBB) || !TryConsume((char)0xBF)) {
AddError("Proto file starts with 0xEF but not UTF-8 BOM. "
"Only UTF-8 is accepted for proto file.");
return false;
}
}
@@ -889,7 +836,9 @@ bool Tokenizer::NextWithComments(std::string* prev_trailing_comments,
collector.DetachFromPrev();
} else {
bool result = Next();
if (!result || current_.text == "}" || current_.text == "]" ||
if (!result ||
current_.text == "}" ||
current_.text == "]" ||
current_.text == ")") {
// It looks like we're at the end of a scope. In this case it
// makes no sense to attach a comment to the following token.
@@ -909,12 +858,12 @@ bool Tokenizer::NextWithComments(std::string* prev_trailing_comments,
// are given is text that the tokenizer actually parsed as a token
// of the given type.
bool Tokenizer::ParseInteger(const std::string& text, uint64_t max_value,
uint64_t* output) {
bool Tokenizer::ParseInteger(const string& text, uint64 max_value,
uint64* output) {
// Sadly, we can't just use strtoul() since it is only 32-bit and strtoull()
// is non-standard. I hate the C standard library. :(
// return strtoull(text.c_str(), NULL, 0);
// return strtoull(text.c_str(), NULL, 0);
const char* ptr = text.c_str();
int base = 10;
@@ -929,7 +878,7 @@ bool Tokenizer::ParseInteger(const std::string& text, uint64_t max_value,
}
}
uint64_t result = 0;
uint64 result = 0;
for (; *ptr != '\0'; ptr++) {
int digit = DigitValue(*ptr);
if (digit < 0 || digit >= base) {
@@ -937,8 +886,7 @@ bool Tokenizer::ParseInteger(const std::string& text, uint64_t max_value,
// token, but Tokenizer still think it's integer.
return false;
}
if (static_cast<uint64_t>(digit) > max_value ||
result > (max_value - digit) / base) {
if (digit > max_value || result > (max_value - digit) / base) {
// Overflow.
return false;
}
@@ -949,7 +897,7 @@ bool Tokenizer::ParseInteger(const std::string& text, uint64_t max_value,
return true;
}
double Tokenizer::ParseFloat(const std::string& text) {
double Tokenizer::ParseFloat(const string& text) {
const char* start = text.c_str();
char* end;
double result = NoLocaleStrtod(start, &end);
@@ -968,38 +916,41 @@ double Tokenizer::ParseFloat(const std::string& text) {
++end;
}
GOOGLE_LOG_IF(DFATAL,
static_cast<size_t>(end - start) != text.size() || *start == '-')
<< " Tokenizer::ParseFloat() passed text that could not have been"
" tokenized as a float: "
<< CEscape(text);
GOOGLE_LOG_IF(DFATAL, end - start != text.size() || *start == '-')
<< " Tokenizer::ParseFloat() passed text that could not have been"
" tokenized as a float: " << CEscape(text);
return result;
}
// Helper to append a Unicode code point to a string as UTF8, without bringing
// in any external dependencies.
static void AppendUTF8(uint32_t code_point, std::string* output) {
uint32_t tmp = 0;
static void AppendUTF8(uint32 code_point, string* output) {
uint32 tmp = 0;
int len = 0;
if (code_point <= 0x7f) {
tmp = code_point;
len = 1;
} else if (code_point <= 0x07ff) {
tmp = 0x0000c080 | ((code_point & 0x07c0) << 2) | (code_point & 0x003f);
tmp = 0x0000c080 |
((code_point & 0x07c0) << 2) |
(code_point & 0x003f);
len = 2;
} else if (code_point <= 0xffff) {
tmp = 0x00e08080 | ((code_point & 0xf000) << 4) |
((code_point & 0x0fc0) << 2) | (code_point & 0x003f);
tmp = 0x00e08080 |
((code_point & 0xf000) << 4) |
((code_point & 0x0fc0) << 2) |
(code_point & 0x003f);
len = 3;
} else if (code_point <= 0x10ffff) {
tmp = 0xf0808080 | ((code_point & 0x1c0000) << 6) |
((code_point & 0x03f000) << 4) | ((code_point & 0x000fc0) << 2) |
(code_point & 0x003f);
} else if (code_point <= 0x1fffff) {
tmp = 0xf0808080 |
((code_point & 0x1c0000) << 6) |
((code_point & 0x03f000) << 4) |
((code_point & 0x000fc0) << 2) |
(code_point & 0x003f);
len = 4;
} else {
// Unicode code points end at 0x10FFFF, so this is out-of-range.
// ConsumeString permits hex values up to 0x1FFFFF, and FetchUnicodePoint
// doesn't perform a range check.
// UTF-16 is only defined for code points up to 0x10FFFF, and UTF-8 is
// normally only defined up to there as well.
StringAppendF(output, "\\U%08x", code_point);
return;
}
@@ -1009,7 +960,7 @@ static void AppendUTF8(uint32_t code_point, std::string* output) {
// Try to read <len> hex digits from ptr, and stuff the numeric result into
// *result. Returns true if that many digits were successfully consumed.
static bool ReadHexDigits(const char* ptr, int len, uint32_t* result) {
static bool ReadHexDigits(const char* ptr, int len, uint32* result) {
*result = 0;
if (len == 0) return false;
for (const char* end = ptr + len; ptr < end; ++ptr) {
@@ -1024,27 +975,26 @@ static bool ReadHexDigits(const char* ptr, int len, uint32_t* result) {
// surrogate. These numbers are in a reserved range of Unicode code points, so
// if we encounter such a pair we know how to parse it and convert it into a
// single code point.
static const uint32_t kMinHeadSurrogate = 0xd800;
static const uint32_t kMaxHeadSurrogate = 0xdc00;
static const uint32_t kMinTrailSurrogate = 0xdc00;
static const uint32_t kMaxTrailSurrogate = 0xe000;
static const uint32 kMinHeadSurrogate = 0xd800;
static const uint32 kMaxHeadSurrogate = 0xdc00;
static const uint32 kMinTrailSurrogate = 0xdc00;
static const uint32 kMaxTrailSurrogate = 0xe000;
static inline bool IsHeadSurrogate(uint32_t code_point) {
static inline bool IsHeadSurrogate(uint32 code_point) {
return (code_point >= kMinHeadSurrogate) && (code_point < kMaxHeadSurrogate);
}
static inline bool IsTrailSurrogate(uint32_t code_point) {
static inline bool IsTrailSurrogate(uint32 code_point) {
return (code_point >= kMinTrailSurrogate) &&
(code_point < kMaxTrailSurrogate);
(code_point < kMaxTrailSurrogate);
}
// Combine a head and trail surrogate into a single Unicode code point.
static uint32_t AssembleUTF16(uint32_t head_surrogate,
uint32_t trail_surrogate) {
static uint32 AssembleUTF16(uint32 head_surrogate, uint32 trail_surrogate) {
GOOGLE_DCHECK(IsHeadSurrogate(head_surrogate));
GOOGLE_DCHECK(IsTrailSurrogate(trail_surrogate));
return 0x10000 + (((head_surrogate - kMinHeadSurrogate) << 10) |
(trail_surrogate - kMinTrailSurrogate));
(trail_surrogate - kMinTrailSurrogate));
}
// Convert the escape sequence parameter to a number of expected hex digits.
@@ -1058,11 +1008,12 @@ static inline int UnicodeLength(char key) {
// to parse that sequence. On success, returns a pointer to the first char
// beyond that sequence, and fills in *code_point. On failure, returns ptr
// itself.
static const char* FetchUnicodePoint(const char* ptr, uint32_t* code_point) {
static const char* FetchUnicodePoint(const char* ptr, uint32* code_point) {
const char* p = ptr;
// Fetch the code point.
const int len = UnicodeLength(*p++);
if (!ReadHexDigits(p, len, code_point)) return ptr;
if (!ReadHexDigits(p, len, code_point))
return ptr;
p += len;
// Check if the code point we read is a "head surrogate." If so, then we
@@ -1070,7 +1021,7 @@ static const char* FetchUnicodePoint(const char* ptr, uint32_t* code_point) {
// "trail surrogate," and together they form a UTF-16 pair which decodes into
// a single Unicode point. Trail surrogates may only use \u, not \U.
if (IsHeadSurrogate(*code_point) && *p == '\\' && *(p + 1) == 'u') {
uint32_t trail_surrogate;
uint32 trail_surrogate;
if (ReadHexDigits(p + 2, 4, &trail_surrogate) &&
IsTrailSurrogate(trail_surrogate)) {
*code_point = AssembleUTF16(*code_point, trail_surrogate);
@@ -1085,15 +1036,14 @@ static const char* FetchUnicodePoint(const char* ptr, uint32_t* code_point) {
// The text string must begin and end with single or double quote
// characters.
void Tokenizer::ParseStringAppend(const std::string& text,
std::string* output) {
void Tokenizer::ParseStringAppend(const string& text, string* output) {
// Reminder: text[0] is always a quote character. (If text is
// empty, it's invalid, so we'll just return).
const size_t text_size = text.size();
if (text_size == 0) {
GOOGLE_LOG(DFATAL) << " Tokenizer::ParseStringAppend() passed text that could not"
" have been tokenized as a string: "
<< CEscape(text);
GOOGLE_LOG(DFATAL)
<< " Tokenizer::ParseStringAppend() passed text that could not"
" have been tokenized as a string: " << CEscape(text);
return;
}
@@ -1142,7 +1092,7 @@ void Tokenizer::ParseStringAppend(const std::string& text,
output->push_back(static_cast<char>(code));
} else if (*ptr == 'u' || *ptr == 'U') {
uint32_t unicode;
uint32 unicode;
const char* end = FetchUnicodePoint(ptr, &unicode);
if (end == ptr) {
// Failure: Just dump out what we saw, don't try to parse it.
@@ -1164,19 +1114,23 @@ void Tokenizer::ParseStringAppend(const std::string& text,
}
}
template <typename CharacterClass>
static bool AllInClass(const std::string& s) {
for (const char character : s) {
if (!CharacterClass::InClass(character)) return false;
template<typename CharacterClass>
static bool AllInClass(const string& s) {
for (int i = 0; i < s.size(); ++i) {
if (!CharacterClass::InClass(s[i]))
return false;
}
return true;
}
bool Tokenizer::IsIdentifier(const std::string& text) {
bool Tokenizer::IsIdentifier(const string& text) {
// Mirrors IDENTIFIER definition in Tokenizer::Next() above.
if (text.size() == 0) return false;
if (!Letter::InClass(text.at(0))) return false;
if (!AllInClass<Alphanumeric>(text.substr(1))) return false;
if (text.size() == 0)
return false;
if (!Letter::InClass(text.at(0)))
return false;
if (!AllInClass<Alphanumeric>(text.substr(1)))
return false;
return true;
}
+42 -71
View File
@@ -37,19 +37,16 @@
#ifndef GOOGLE_PROTOBUF_IO_TOKENIZER_H__
#define GOOGLE_PROTOBUF_IO_TOKENIZER_H__
#include <string>
#include <vector>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/port_def.inc>
namespace google {
namespace protobuf {
namespace io {
class ZeroCopyInputStream; // zero_copy_stream.h
class ZeroCopyInputStream; // zero_copy_stream.h
// Defined in this file.
class ErrorCollector;
@@ -64,7 +61,7 @@ typedef int ColumnNumber;
// Abstract interface for an object which collects the errors that occur
// during parsing. A typical implementation might simply print the errors
// to stdout.
class PROTOBUF_EXPORT ErrorCollector {
class LIBPROTOBUF_EXPORT ErrorCollector {
public:
inline ErrorCollector() {}
virtual ~ErrorCollector();
@@ -73,13 +70,13 @@ class PROTOBUF_EXPORT ErrorCollector {
// column numbers. The numbers are zero-based, so you may want to add
// 1 to each before printing them.
virtual void AddError(int line, ColumnNumber column,
const std::string& message) = 0;
const string& message) = 0;
// Indicates that there was a warning in the input at the given line and
// column numbers. The numbers are zero-based, so you may want to add
// 1 to each before printing them.
virtual void AddWarning(int /* line */, ColumnNumber /* column */,
const std::string& /* message */) {}
virtual void AddWarning(int line, ColumnNumber column,
const string& message) { }
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector);
@@ -91,7 +88,7 @@ class PROTOBUF_EXPORT ErrorCollector {
// precise descriptions. Whitespace and comments are skipped. By default,
// C- and C++-style comments are recognized, but other styles can be used by
// calling set_comment_style().
class PROTOBUF_EXPORT Tokenizer {
class LIBPROTOBUF_EXPORT Tokenizer {
public:
// Construct a Tokenizer that reads and tokenizes text from the given
// input stream and writes errors to the given error_collector.
@@ -100,8 +97,8 @@ class PROTOBUF_EXPORT Tokenizer {
~Tokenizer();
enum TokenType {
TYPE_START, // Next() has not yet been called.
TYPE_END, // End of input reached. "text" is empty.
TYPE_START, // Next() has not yet been called.
TYPE_END, // End of input reached. "text" is empty.
TYPE_IDENTIFIER, // A sequence of letters, digits, and underscores, not
// starting with a digit. It is an error for a number
@@ -122,19 +119,12 @@ class PROTOBUF_EXPORT Tokenizer {
TYPE_SYMBOL, // Any other printable character, like '!' or '+'.
// Symbols are always a single character, so "!+$%" is
// four tokens.
TYPE_WHITESPACE, // A sequence of whitespace. This token type is only
// produced if report_whitespace() is true. It is not
// reported for whitespace within comments or strings.
TYPE_NEWLINE, // A newline (\n). This token type is only
// produced if report_whitespace() is true and
// report_newlines() is true. It is not reported for
// newlines in comments or strings.
};
// Structure representing a token read from the token stream.
struct Token {
TokenType type;
std::string text; // The exact text of the token as it appeared in
string text; // The exact text of the token as it appeared in
// the input. e.g. tokens of TYPE_STRING will still
// be escaped and in quotes.
@@ -200,32 +190,32 @@ class PROTOBUF_EXPORT Tokenizer {
// /* Block comment attached to
// * grault. */
// optional int32 grault = 6;
bool NextWithComments(std::string* prev_trailing_comments,
std::vector<std::string>* detached_comments,
std::string* next_leading_comments);
bool NextWithComments(string* prev_trailing_comments,
std::vector<string>* detached_comments,
string* next_leading_comments);
// Parse helpers ---------------------------------------------------
// Parses a TYPE_FLOAT token. This never fails, so long as the text actually
// comes from a TYPE_FLOAT token parsed by Tokenizer. If it doesn't, the
// result is undefined (possibly an assert failure).
static double ParseFloat(const std::string& text);
static double ParseFloat(const string& text);
// Parses a TYPE_STRING token. This never fails, so long as the text actually
// comes from a TYPE_STRING token parsed by Tokenizer. If it doesn't, the
// result is undefined (possibly an assert failure).
static void ParseString(const std::string& text, std::string* output);
static void ParseString(const string& text, string* output);
// Identical to ParseString, but appends to output.
static void ParseStringAppend(const std::string& text, std::string* output);
static void ParseStringAppend(const string& text, string* output);
// Parses a TYPE_INTEGER token. Returns false if the result would be
// greater than max_value. Otherwise, returns true and sets *output to the
// result. If the text is not from a Token of type TYPE_INTEGER originally
// parsed by a Tokenizer, the result is undefined (possibly an assert
// failure).
static bool ParseInteger(const std::string& text, uint64_t max_value,
uint64_t* output);
static bool ParseInteger(const string& text, uint64 max_value,
uint64* output);
// Options ---------------------------------------------------------
@@ -259,34 +249,24 @@ class PROTOBUF_EXPORT Tokenizer {
allow_multiline_strings_ = allow;
}
// If true, whitespace tokens are reported by Next().
// Note: `set_report_whitespace(false)` implies `set_report_newlines(false)`.
bool report_whitespace() const;
void set_report_whitespace(bool report);
// If true, newline tokens are reported by Next().
// Note: `set_report_newlines(true)` implies `set_report_whitespace(true)`.
bool report_newlines() const;
void set_report_newlines(bool report);
// External helper: validate an identifier.
static bool IsIdentifier(const std::string& text);
static bool IsIdentifier(const string& text);
// -----------------------------------------------------------------
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Tokenizer);
Token current_; // Returned by current().
Token previous_; // Returned by previous().
Token current_; // Returned by current().
Token previous_; // Returned by previous().
ZeroCopyInputStream* input_;
ErrorCollector* error_collector_;
char current_char_; // == buffer_[buffer_pos_], updated by NextChar().
const char* buffer_; // Current buffer returned from input_.
int buffer_size_; // Size of buffer_.
int buffer_pos_; // Current position within the buffer.
bool read_error_; // Did we previously encounter a read error?
char current_char_; // == buffer_[buffer_pos_], updated by NextChar().
const char* buffer_; // Current buffer returned from input_.
int buffer_size_; // Size of buffer_.
int buffer_pos_; // Current position within the buffer.
bool read_error_; // Did we previously encounter a read error?
// Line and column number of current_char_ within the whole input stream.
int line_;
@@ -296,7 +276,7 @@ class PROTOBUF_EXPORT Tokenizer {
// Call RecordTo(&str) to start recording and StopRecording() to stop.
// E.g. StartToken() calls RecordTo(&current_.text). record_start_ is the
// position within the current buffer where recording started.
std::string* record_target_;
string* record_target_;
int record_start_;
// Options.
@@ -304,8 +284,6 @@ class PROTOBUF_EXPORT Tokenizer {
CommentStyle comment_style_;
bool require_space_after_number_;
bool allow_multiline_strings_;
bool report_whitespace_ = false;
bool report_newlines_ = false;
// Since we count columns we need to interpret tabs somehow. We'll take
// the standard 8-character definition for lack of any way to do better.
@@ -321,7 +299,7 @@ class PROTOBUF_EXPORT Tokenizer {
// Read a new buffer from the input.
void Refresh();
inline void RecordTo(std::string* target);
inline void RecordTo(string* target);
inline void StopRecording();
// Called when the current character is the first character of a new
@@ -333,7 +311,7 @@ class PROTOBUF_EXPORT Tokenizer {
inline void EndToken();
// Convenience method to add an error at the current line and column.
void AddError(const std::string& message) {
void AddError(const string& message) {
error_collector_->AddError(line_, column_, message);
}
@@ -356,9 +334,9 @@ class PROTOBUF_EXPORT Tokenizer {
TokenType ConsumeNumber(bool started_with_zero, bool started_with_dot);
// Consume the rest of a line.
void ConsumeLineComment(std::string* content);
void ConsumeLineComment(string* content);
// Consume until "*/".
void ConsumeBlockComment(std::string* content);
void ConsumeBlockComment(string* content);
enum NextCommentStatus {
// Started a line comment.
@@ -379,14 +357,6 @@ class PROTOBUF_EXPORT Tokenizer {
// of comment it is.
NextCommentStatus TryConsumeCommentStart();
// If we're looking at a TYPE_WHITESPACE token and `report_whitespace_` is
// true, consume it and return true.
bool TryConsumeWhitespace();
// If we're looking at a TYPE_NEWLINE token and `report_newlines_` is true,
// consume it and return true.
bool TryConsumeNewline();
// -----------------------------------------------------------------
// These helper methods make the parsing code more readable. The
// "character classes" referred to are defined at the top of the .cc file.
@@ -397,44 +367,45 @@ class PROTOBUF_EXPORT Tokenizer {
// Returns true if the current character is of the given character
// class, but does not consume anything.
template <typename CharacterClass>
template<typename CharacterClass>
inline bool LookingAt();
// If the current character is in the given class, consume it and return
// true. Otherwise return false.
// e.g. TryConsumeOne<Letter>()
template <typename CharacterClass>
template<typename CharacterClass>
inline bool TryConsumeOne();
// Like above, but try to consume the specific character indicated.
inline bool TryConsume(char c);
// Consume zero or more of the given character class.
template <typename CharacterClass>
template<typename CharacterClass>
inline void ConsumeZeroOrMore();
// Consume one or more of the given character class or log the given
// error message.
// e.g. ConsumeOneOrMore<Digit>("Expected digits.");
template <typename CharacterClass>
template<typename CharacterClass>
inline void ConsumeOneOrMore(const char* error);
};
// inline methods ====================================================
inline const Tokenizer::Token& Tokenizer::current() { return current_; }
inline const Tokenizer::Token& Tokenizer::current() {
return current_;
}
inline const Tokenizer::Token& Tokenizer::previous() { return previous_; }
inline const Tokenizer::Token& Tokenizer::previous() {
return previous_;
}
inline void Tokenizer::ParseString(const std::string& text,
std::string* output) {
inline void Tokenizer::ParseString(const string& text, string* output) {
output->clear();
ParseStringAppend(text, output);
}
} // namespace io
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_IO_TOKENIZER_H__
+6 -11
View File
@@ -107,14 +107,11 @@
#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/port_def.inc>
namespace google {
namespace protobuf {
namespace io {
@@ -124,7 +121,7 @@ class ZeroCopyOutputStream;
// Abstract interface similar to an input stream but designed to minimize
// copying.
class PROTOBUF_EXPORT ZeroCopyInputStream {
class LIBPROTOBUF_EXPORT ZeroCopyInputStream {
public:
ZeroCopyInputStream() {}
virtual ~ZeroCopyInputStream() {}
@@ -172,7 +169,7 @@ class PROTOBUF_EXPORT ZeroCopyInputStream {
virtual bool Skip(int count) = 0;
// Returns the total number of bytes read since this object was created.
virtual int64_t ByteCount() const = 0;
virtual int64 ByteCount() const = 0;
private:
@@ -181,7 +178,7 @@ class PROTOBUF_EXPORT ZeroCopyInputStream {
// Abstract interface similar to an output stream but designed to minimize
// copying.
class PROTOBUF_EXPORT ZeroCopyOutputStream {
class LIBPROTOBUF_EXPORT ZeroCopyOutputStream {
public:
ZeroCopyOutputStream() {}
virtual ~ZeroCopyOutputStream() {}
@@ -227,7 +224,7 @@ class PROTOBUF_EXPORT ZeroCopyOutputStream {
virtual void BackUp(int count) = 0;
// Returns the total number of bytes written since this object was created.
virtual int64_t ByteCount() const = 0;
virtual int64 ByteCount() const = 0;
// Write a given chunk of data to the output. Some output streams may
// implement this in a way that avoids copying. Check AllowsAliasing() before
@@ -246,8 +243,6 @@ class PROTOBUF_EXPORT ZeroCopyOutputStream {
} // namespace io
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
@@ -33,21 +33,19 @@
// Sanjay Ghemawat, Jeff Dean, and others.
#ifndef _MSC_VER
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif
#include <errno.h>
#include <algorithm>
#include <iostream>
#include <algorithm>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/io/io_win32.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/stubs/stl_util.h>
#include <google/protobuf/stubs/io_win32.h>
namespace google {
@@ -60,11 +58,11 @@ namespace io {
#define lseek(fd, offset, origin) ((off_t)-1)
// DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
// them like we do below.
using google::protobuf::io::win32::access;
using google::protobuf::io::win32::close;
using google::protobuf::io::win32::open;
using google::protobuf::io::win32::read;
using google::protobuf::io::win32::write;
using google::protobuf::internal::win32::access;
using google::protobuf::internal::win32::close;
using google::protobuf::internal::win32::open;
using google::protobuf::internal::win32::read;
using google::protobuf::internal::win32::write;
#endif
namespace {
@@ -80,35 +78,41 @@ int close_no_eintr(int fd) {
} // namespace
// ===================================================================
FileInputStream::FileInputStream(int file_descriptor, int block_size)
: copying_input_(file_descriptor), impl_(&copying_input_, block_size) {}
: copying_input_(file_descriptor),
impl_(&copying_input_, block_size) {
}
bool FileInputStream::Close() { return copying_input_.Close(); }
bool FileInputStream::Close() {
return copying_input_.Close();
}
bool FileInputStream::Next(const void** data, int* size) {
return impl_.Next(data, size);
}
void FileInputStream::BackUp(int count) { impl_.BackUp(count); }
void FileInputStream::BackUp(int count) {
impl_.BackUp(count);
}
bool FileInputStream::Skip(int count) { return impl_.Skip(count); }
bool FileInputStream::Skip(int count) {
return impl_.Skip(count);
}
int64_t FileInputStream::ByteCount() const { return impl_.ByteCount(); }
int64 FileInputStream::ByteCount() const {
return impl_.ByteCount();
}
FileInputStream::CopyingFileInputStream::CopyingFileInputStream(
int file_descriptor)
: file_(file_descriptor),
close_on_delete_(false),
is_closed_(false),
errno_(0),
previous_seek_failed_(false) {
#ifndef _WIN32
int flags = fcntl(file_, F_GETFL);
flags &= ~O_NONBLOCK;
fcntl(file_, F_SETFL, flags);
#endif
: file_(file_descriptor),
close_on_delete_(false),
is_closed_(false),
errno_(0),
previous_seek_failed_(false) {
}
FileInputStream::CopyingFileInputStream::~CopyingFileInputStream() {
@@ -153,7 +157,8 @@ int FileInputStream::CopyingFileInputStream::Read(void* buffer, int size) {
int FileInputStream::CopyingFileInputStream::Skip(int count) {
GOOGLE_CHECK(!is_closed_);
if (!previous_seek_failed_ && lseek(file_, count, SEEK_CUR) != (off_t)-1) {
if (!previous_seek_failed_ &&
lseek(file_, count, SEEK_CUR) != (off_t)-1) {
// Seek succeeded.
return count;
} else {
@@ -170,23 +175,43 @@ int FileInputStream::CopyingFileInputStream::Skip(int count) {
// ===================================================================
FileOutputStream::FileOutputStream(int file_descriptor, int /*block_size*/)
: CopyingOutputStreamAdaptor(&copying_output_),
copying_output_(file_descriptor) {}
FileOutputStream::FileOutputStream(int file_descriptor, int block_size)
: copying_output_(file_descriptor),
impl_(&copying_output_, block_size) {
}
FileOutputStream::~FileOutputStream() {
impl_.Flush();
}
bool FileOutputStream::Close() {
bool flush_succeeded = Flush();
bool flush_succeeded = impl_.Flush();
return copying_output_.Close() && flush_succeeded;
}
bool FileOutputStream::Flush() {
return impl_.Flush();
}
bool FileOutputStream::Next(void** data, int* size) {
return impl_.Next(data, size);
}
void FileOutputStream::BackUp(int count) {
impl_.BackUp(count);
}
int64 FileOutputStream::ByteCount() const {
return impl_.ByteCount();
}
FileOutputStream::CopyingFileOutputStream::CopyingFileOutputStream(
int file_descriptor)
: file_(file_descriptor),
close_on_delete_(false),
is_closed_(false),
errno_(0) {}
FileOutputStream::~FileOutputStream() { Flush(); }
: file_(file_descriptor),
close_on_delete_(false),
is_closed_(false),
errno_(0) {
}
FileOutputStream::CopyingFileOutputStream::~CopyingFileOutputStream() {
if (close_on_delete_) {
@@ -211,12 +236,12 @@ bool FileOutputStream::CopyingFileOutputStream::Close() {
return true;
}
bool FileOutputStream::CopyingFileOutputStream::Write(const void* buffer,
int size) {
bool FileOutputStream::CopyingFileOutputStream::Write(
const void* buffer, int size) {
GOOGLE_CHECK(!is_closed_);
int total_written = 0;
const uint8_t* buffer_base = reinterpret_cast<const uint8_t*>(buffer);
const uint8* buffer_base = reinterpret_cast<const uint8*>(buffer);
while (total_written < size) {
int bytes;
@@ -255,11 +280,17 @@ bool IstreamInputStream::Next(const void** data, int* size) {
return impl_.Next(data, size);
}
void IstreamInputStream::BackUp(int count) { impl_.BackUp(count); }
void IstreamInputStream::BackUp(int count) {
impl_.BackUp(count);
}
bool IstreamInputStream::Skip(int count) { return impl_.Skip(count); }
bool IstreamInputStream::Skip(int count) {
return impl_.Skip(count);
}
int64_t IstreamInputStream::ByteCount() const { return impl_.ByteCount(); }
int64 IstreamInputStream::ByteCount() const {
return impl_.ByteCount();
}
IstreamInputStream::CopyingIstreamInputStream::CopyingIstreamInputStream(
std::istream* input)
@@ -267,8 +298,8 @@ IstreamInputStream::CopyingIstreamInputStream::CopyingIstreamInputStream(
IstreamInputStream::CopyingIstreamInputStream::~CopyingIstreamInputStream() {}
int IstreamInputStream::CopyingIstreamInputStream::Read(void* buffer,
int size) {
int IstreamInputStream::CopyingIstreamInputStream::Read(
void* buffer, int size) {
input_->read(reinterpret_cast<char*>(buffer), size);
int result = input_->gcount();
if (result == 0 && input_->fail() && !input_->eof()) {
@@ -282,15 +313,21 @@ int IstreamInputStream::CopyingIstreamInputStream::Read(void* buffer,
OstreamOutputStream::OstreamOutputStream(std::ostream* output, int block_size)
: copying_output_(output), impl_(&copying_output_, block_size) {}
OstreamOutputStream::~OstreamOutputStream() { impl_.Flush(); }
OstreamOutputStream::~OstreamOutputStream() {
impl_.Flush();
}
bool OstreamOutputStream::Next(void** data, int* size) {
return impl_.Next(data, size);
}
void OstreamOutputStream::BackUp(int count) { impl_.BackUp(count); }
void OstreamOutputStream::BackUp(int count) {
impl_.BackUp(count);
}
int64_t OstreamOutputStream::ByteCount() const { return impl_.ByteCount(); }
int64 OstreamOutputStream::ByteCount() const {
return impl_.ByteCount();
}
OstreamOutputStream::CopyingOstreamOutputStream::CopyingOstreamOutputStream(
std::ostream* output)
@@ -299,8 +336,8 @@ OstreamOutputStream::CopyingOstreamOutputStream::CopyingOstreamOutputStream(
OstreamOutputStream::CopyingOstreamOutputStream::~CopyingOstreamOutputStream() {
}
bool OstreamOutputStream::CopyingOstreamOutputStream::Write(const void* buffer,
int size) {
bool OstreamOutputStream::CopyingOstreamOutputStream::Write(
const void* buffer, int size) {
output_->write(reinterpret_cast<const char*>(buffer), size);
return output_->good();
}
@@ -309,7 +346,7 @@ bool OstreamOutputStream::CopyingOstreamOutputStream::Write(const void* buffer,
ConcatenatingInputStream::ConcatenatingInputStream(
ZeroCopyInputStream* const streams[], int count)
: streams_(streams), stream_count_(count), bytes_retired_(0) {
: streams_(streams), stream_count_(count), bytes_retired_(0) {
}
bool ConcatenatingInputStream::Next(const void** data, int* size) {
@@ -338,12 +375,12 @@ bool ConcatenatingInputStream::Skip(int count) {
while (stream_count_ > 0) {
// Assume that ByteCount() can be used to find out how much we actually
// skipped when Skip() fails.
int64_t target_byte_count = streams_[0]->ByteCount() + count;
int64 target_byte_count = streams_[0]->ByteCount() + count;
if (streams_[0]->Skip(count)) return true;
// Hit the end of the stream. Figure out how many more bytes we still have
// to skip.
int64_t final_byte_count = streams_[0]->ByteCount();
int64 final_byte_count = streams_[0]->ByteCount();
GOOGLE_DCHECK_LT(final_byte_count, target_byte_count);
count = target_byte_count - final_byte_count;
@@ -356,7 +393,7 @@ bool ConcatenatingInputStream::Skip(int count) {
return false;
}
int64_t ConcatenatingInputStream::ByteCount() const {
int64 ConcatenatingInputStream::ByteCount() const {
if (stream_count_ == 0) {
return bytes_retired_;
} else {
@@ -365,6 +402,63 @@ int64_t ConcatenatingInputStream::ByteCount() const {
}
// ===================================================================
LimitingInputStream::LimitingInputStream(ZeroCopyInputStream* input,
int64 limit)
: input_(input), limit_(limit) {
prior_bytes_read_ = input_->ByteCount();
}
LimitingInputStream::~LimitingInputStream() {
// If we overshot the limit, back up.
if (limit_ < 0) input_->BackUp(-limit_);
}
bool LimitingInputStream::Next(const void** data, int* size) {
if (limit_ <= 0) return false;
if (!input_->Next(data, size)) return false;
limit_ -= *size;
if (limit_ < 0) {
// We overshot the limit. Reduce *size to hide the rest of the buffer.
*size += limit_;
}
return true;
}
void LimitingInputStream::BackUp(int count) {
if (limit_ < 0) {
input_->BackUp(count - limit_);
limit_ = count;
} else {
input_->BackUp(count);
limit_ += count;
}
}
bool LimitingInputStream::Skip(int count) {
if (count > limit_) {
if (limit_ < 0) return false;
input_->Skip(limit_);
limit_ = 0;
return false;
} else {
if (!input_->Skip(count)) return false;
limit_ -= count;
return true;
}
}
int64 LimitingInputStream::ByteCount() const {
if (limit_ < 0) {
return input_->ByteCount() + limit_ - prior_bytes_read_;
} else {
return input_->ByteCount() - prior_bytes_read_;
}
}
// ===================================================================
} // namespace io
@@ -40,20 +40,18 @@
#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
#include <iosfwd>
#include <string>
#include <google/protobuf/stubs/common.h>
#include <iosfwd>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/port_def.inc>
namespace google {
namespace protobuf {
namespace io {
// ===================================================================
// A ZeroCopyInputStream which reads from a file descriptor.
@@ -62,7 +60,7 @@ namespace io {
// The latter will introduce an extra layer of buffering, harming performance.
// Also, it's conceivable that FileInputStream could someday be enhanced
// to use zero-copy file descriptors on OSs which support them.
class PROTOBUF_EXPORT FileInputStream : public ZeroCopyInputStream {
class LIBPROTOBUF_EXPORT FileInputStream : public ZeroCopyInputStream {
public:
// Creates a stream that reads from the given Unix file descriptor.
// If a block_size is given, it specifies the number of bytes that
@@ -86,27 +84,27 @@ class PROTOBUF_EXPORT FileInputStream : public ZeroCopyInputStream {
// errno from that error. Otherwise, this is zero. Once an error
// occurs, the stream is broken and all subsequent operations will
// fail.
int GetErrno() const { return copying_input_.GetErrno(); }
int GetErrno() { return copying_input_.GetErrno(); }
// implements ZeroCopyInputStream ----------------------------------
bool Next(const void** data, int* size) override;
void BackUp(int count) override;
bool Skip(int count) override;
int64_t ByteCount() const override;
bool Next(const void** data, int* size);
void BackUp(int count);
bool Skip(int count);
int64 ByteCount() const;
private:
class PROTOBUF_EXPORT CopyingFileInputStream : public CopyingInputStream {
class LIBPROTOBUF_EXPORT CopyingFileInputStream : public CopyingInputStream {
public:
CopyingFileInputStream(int file_descriptor);
~CopyingFileInputStream() override;
~CopyingFileInputStream();
bool Close();
void SetCloseOnDelete(bool value) { close_on_delete_ = value; }
int GetErrno() const { return errno_; }
int GetErrno() { return errno_; }
// implements CopyingInputStream ---------------------------------
int Read(void* buffer, int size) override;
int Skip(int count) override;
int Read(void* buffer, int size);
int Skip(int count);
private:
// The file descriptor.
@@ -139,21 +137,25 @@ class PROTOBUF_EXPORT FileInputStream : public ZeroCopyInputStream {
// harming performance. Also, it's conceivable that FileOutputStream could
// someday be enhanced to use zero-copy file descriptors on OSs which
// support them.
class PROTOBUF_EXPORT FileOutputStream : public CopyingOutputStreamAdaptor {
class LIBPROTOBUF_EXPORT FileOutputStream : public ZeroCopyOutputStream {
public:
// Creates a stream that writes to the given Unix file descriptor.
// If a block_size is given, it specifies the size of the buffers
// that should be returned by Next(). Otherwise, a reasonable default
// is used.
explicit FileOutputStream(int file_descriptor, int block_size = -1);
~FileOutputStream() override;
~FileOutputStream();
// Flushes any buffers and closes the underlying file. Returns false if
// an error occurs during the process; use GetErrno() to examine the error.
// Even if an error occurs, the file descriptor is closed when this returns.
bool Close();
// Flushes FileOutputStream's buffers but does not close the
// underlying file. No special measures are taken to ensure that
// underlying operating system file object is synchronized to disk.
bool Flush();
// By default, the file descriptor is not closed when the stream is
// destroyed. Call SetCloseOnDelete(true) to change that. WARNING:
// This leaves no way for the caller to detect if close() fails. If
@@ -165,20 +167,25 @@ class PROTOBUF_EXPORT FileOutputStream : public CopyingOutputStreamAdaptor {
// errno from that error. Otherwise, this is zero. Once an error
// occurs, the stream is broken and all subsequent operations will
// fail.
int GetErrno() const { return copying_output_.GetErrno(); }
int GetErrno() { return copying_output_.GetErrno(); }
// implements ZeroCopyOutputStream ---------------------------------
bool Next(void** data, int* size);
void BackUp(int count);
int64 ByteCount() const;
private:
class PROTOBUF_EXPORT CopyingFileOutputStream : public CopyingOutputStream {
class LIBPROTOBUF_EXPORT CopyingFileOutputStream : public CopyingOutputStream {
public:
CopyingFileOutputStream(int file_descriptor);
~CopyingFileOutputStream() override;
~CopyingFileOutputStream();
bool Close();
void SetCloseOnDelete(bool value) { close_on_delete_ = value; }
int GetErrno() const { return errno_; }
int GetErrno() { return errno_; }
// implements CopyingOutputStream --------------------------------
bool Write(const void* buffer, int size) override;
bool Write(const void* buffer, int size);
private:
// The file descriptor.
@@ -193,6 +200,7 @@ class PROTOBUF_EXPORT FileOutputStream : public CopyingOutputStreamAdaptor {
};
CopyingFileOutputStream copying_output_;
CopyingOutputStreamAdaptor impl_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileOutputStream);
};
@@ -203,7 +211,7 @@ class PROTOBUF_EXPORT FileOutputStream : public CopyingOutputStreamAdaptor {
//
// Note that for reading files (or anything represented by a file descriptor),
// FileInputStream is more efficient.
class PROTOBUF_EXPORT IstreamInputStream : public ZeroCopyInputStream {
class LIBPROTOBUF_EXPORT IstreamInputStream : public ZeroCopyInputStream {
public:
// Creates a stream that reads from the given C++ istream.
// If a block_size is given, it specifies the number of bytes that
@@ -212,19 +220,19 @@ class PROTOBUF_EXPORT IstreamInputStream : public ZeroCopyInputStream {
explicit IstreamInputStream(std::istream* stream, int block_size = -1);
// implements ZeroCopyInputStream ----------------------------------
bool Next(const void** data, int* size) override;
void BackUp(int count) override;
bool Skip(int count) override;
int64_t ByteCount() const override;
bool Next(const void** data, int* size);
void BackUp(int count);
bool Skip(int count);
int64 ByteCount() const;
private:
class PROTOBUF_EXPORT CopyingIstreamInputStream : public CopyingInputStream {
class LIBPROTOBUF_EXPORT CopyingIstreamInputStream : public CopyingInputStream {
public:
CopyingIstreamInputStream(std::istream* input);
~CopyingIstreamInputStream() override;
~CopyingIstreamInputStream();
// implements CopyingInputStream ---------------------------------
int Read(void* buffer, int size) override;
int Read(void* buffer, int size);
// (We use the default implementation of Skip().)
private:
@@ -246,29 +254,28 @@ class PROTOBUF_EXPORT IstreamInputStream : public ZeroCopyInputStream {
//
// Note that for writing files (or anything represented by a file descriptor),
// FileOutputStream is more efficient.
class PROTOBUF_EXPORT OstreamOutputStream : public ZeroCopyOutputStream {
class LIBPROTOBUF_EXPORT OstreamOutputStream : public ZeroCopyOutputStream {
public:
// Creates a stream that writes to the given C++ ostream.
// If a block_size is given, it specifies the size of the buffers
// that should be returned by Next(). Otherwise, a reasonable default
// is used.
explicit OstreamOutputStream(std::ostream* stream, int block_size = -1);
~OstreamOutputStream() override;
~OstreamOutputStream();
// implements ZeroCopyOutputStream ---------------------------------
bool Next(void** data, int* size) override;
void BackUp(int count) override;
int64_t ByteCount() const override;
bool Next(void** data, int* size);
void BackUp(int count);
int64 ByteCount() const;
private:
class PROTOBUF_EXPORT CopyingOstreamOutputStream
: public CopyingOutputStream {
class LIBPROTOBUF_EXPORT CopyingOstreamOutputStream : public CopyingOutputStream {
public:
CopyingOstreamOutputStream(std::ostream* output);
~CopyingOstreamOutputStream() override;
~CopyingOstreamOutputStream();
// implements CopyingOutputStream --------------------------------
bool Write(const void* buffer, int size) override;
bool Write(const void* buffer, int size);
private:
// The stream.
@@ -292,18 +299,17 @@ class PROTOBUF_EXPORT OstreamOutputStream : public ZeroCopyOutputStream {
// ConcatenatingInputStream may do odd things. It is suggested that you do
// not use ConcatenatingInputStream on streams that might produce read errors
// other than end-of-stream.
class PROTOBUF_EXPORT ConcatenatingInputStream : public ZeroCopyInputStream {
class LIBPROTOBUF_EXPORT ConcatenatingInputStream : public ZeroCopyInputStream {
public:
// All streams passed in as well as the array itself must remain valid
// until the ConcatenatingInputStream is destroyed.
ConcatenatingInputStream(ZeroCopyInputStream* const streams[], int count);
~ConcatenatingInputStream() override = default;
// implements ZeroCopyInputStream ----------------------------------
bool Next(const void** data, int* size) override;
void BackUp(int count) override;
bool Skip(int count) override;
int64_t ByteCount() const override;
bool Next(const void** data, int* size);
void BackUp(int count);
bool Skip(int count);
int64 ByteCount() const;
private:
@@ -311,17 +317,39 @@ class PROTOBUF_EXPORT ConcatenatingInputStream : public ZeroCopyInputStream {
// decremented.
ZeroCopyInputStream* const* streams_;
int stream_count_;
int64_t bytes_retired_; // Bytes read from previous streams.
int64 bytes_retired_; // Bytes read from previous streams.
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ConcatenatingInputStream);
};
// ===================================================================
// A ZeroCopyInputStream which wraps some other stream and limits it to
// a particular byte count.
class LIBPROTOBUF_EXPORT LimitingInputStream : public ZeroCopyInputStream {
public:
LimitingInputStream(ZeroCopyInputStream* input, int64 limit);
~LimitingInputStream();
// implements ZeroCopyInputStream ----------------------------------
bool Next(const void** data, int* size);
void BackUp(int count);
bool Skip(int count);
int64 ByteCount() const;
private:
ZeroCopyInputStream* input_;
int64 limit_; // Decreases as we go, becomes negative if we overshoot.
int64 prior_bytes_read_; // Bytes read on underlying stream at construction
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LimitingInputStream);
};
// ===================================================================
} // namespace io
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
@@ -37,9 +37,9 @@
#include <algorithm>
#include <limits>
#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/stubs/stl_util.h>
namespace google {
@@ -55,12 +55,14 @@ static const int kDefaultBlockSize = 8192;
// ===================================================================
ArrayInputStream::ArrayInputStream(const void* data, int size, int block_size)
: data_(reinterpret_cast<const uint8_t*>(data)),
size_(size),
block_size_(block_size > 0 ? block_size : size),
position_(0),
last_returned_size_(0) {}
ArrayInputStream::ArrayInputStream(const void* data, int size,
int block_size)
: data_(reinterpret_cast<const uint8*>(data)),
size_(size),
block_size_(block_size > 0 ? block_size : size),
position_(0),
last_returned_size_(0) {
}
bool ArrayInputStream::Next(const void** data, int* size) {
if (position_ < size_) {
@@ -71,7 +73,7 @@ bool ArrayInputStream::Next(const void** data, int* size) {
return true;
} else {
// We're at the end of the array.
last_returned_size_ = 0; // Don't let caller back up.
last_returned_size_ = 0; // Don't let caller back up.
return false;
}
}
@@ -87,7 +89,7 @@ void ArrayInputStream::BackUp(int count) {
bool ArrayInputStream::Skip(int count) {
GOOGLE_CHECK_GE(count, 0);
last_returned_size_ = 0; // Don't let caller back up.
last_returned_size_ = 0; // Don't let caller back up.
if (count > size_ - position_) {
position_ = size_;
return false;
@@ -97,17 +99,20 @@ bool ArrayInputStream::Skip(int count) {
}
}
int64_t ArrayInputStream::ByteCount() const { return position_; }
int64 ArrayInputStream::ByteCount() const {
return position_;
}
// ===================================================================
ArrayOutputStream::ArrayOutputStream(void* data, int size, int block_size)
: data_(reinterpret_cast<uint8_t*>(data)),
size_(size),
block_size_(block_size > 0 ? block_size : size),
position_(0),
last_returned_size_(0) {}
: data_(reinterpret_cast<uint8*>(data)),
size_(size),
block_size_(block_size > 0 ? block_size : size),
position_(0),
last_returned_size_(0) {
}
bool ArrayOutputStream::Next(void** data, int* size) {
if (position_ < size_) {
@@ -118,7 +123,7 @@ bool ArrayOutputStream::Next(void** data, int* size) {
return true;
} else {
// We're at the end of the array.
last_returned_size_ = 0; // Don't let caller back up.
last_returned_size_ = 0; // Don't let caller back up.
return false;
}
}
@@ -132,33 +137,41 @@ void ArrayOutputStream::BackUp(int count) {
last_returned_size_ = 0; // Don't let caller back up further.
}
int64_t ArrayOutputStream::ByteCount() const { return position_; }
int64 ArrayOutputStream::ByteCount() const {
return position_;
}
// ===================================================================
StringOutputStream::StringOutputStream(std::string* target) : target_(target) {}
StringOutputStream::StringOutputStream(string* target)
: target_(target) {
}
bool StringOutputStream::Next(void** data, int* size) {
GOOGLE_CHECK(target_ != NULL);
size_t old_size = target_->size();
int old_size = target_->size();
// Grow the string.
size_t new_size;
if (old_size < target_->capacity()) {
// Resize the string to match its capacity, since we can get away
// without a memory allocation this way.
new_size = target_->capacity();
STLStringResizeUninitialized(target_, target_->capacity());
} else {
// Size has reached capacity, try to double it.
new_size = old_size * 2;
// Size has reached capacity, try to double the size.
if (old_size > std::numeric_limits<int>::max() / 2) {
// Can not double the size otherwise it is going to cause integer
// overflow in the expression below: old_size * 2 ";
GOOGLE_LOG(ERROR) << "Cannot allocate buffer larger than kint32max for "
<< "StringOutputStream.";
return false;
}
// Double the size, also make sure that the new size is at least
// kMinimumSize.
STLStringResizeUninitialized(
target_,
std::max(old_size * 2,
kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness.
}
// Avoid integer overflow in returned '*size'.
new_size = std::min(new_size, old_size + std::numeric_limits<int>::max());
// Increase the size, also make sure that it is at least kMinimumSize.
STLStringResizeUninitialized(
target_,
std::max(new_size,
kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness.
*data = mutable_string_data(target_) + old_size;
*size = target_->size() - old_size;
@@ -168,23 +181,27 @@ bool StringOutputStream::Next(void** data, int* size) {
void StringOutputStream::BackUp(int count) {
GOOGLE_CHECK_GE(count, 0);
GOOGLE_CHECK(target_ != NULL);
GOOGLE_CHECK_LE(static_cast<size_t>(count), target_->size());
GOOGLE_CHECK_LE(count, target_->size());
target_->resize(target_->size() - count);
}
int64_t StringOutputStream::ByteCount() const {
int64 StringOutputStream::ByteCount() const {
GOOGLE_CHECK(target_ != NULL);
return target_->size();
}
void StringOutputStream::SetString(string* target) {
target_ = target;
}
// ===================================================================
int CopyingInputStream::Skip(int count) {
char junk[4096];
int skipped = 0;
while (skipped < count) {
int bytes = Read(junk, std::min(count - skipped,
implicit_cast<int>(sizeof(junk))));
int bytes =
Read(junk, std::min(count - skipped, implicit_cast<int>(sizeof(junk))));
if (bytes <= 0) {
// EOF or read error.
return skipped;
@@ -196,13 +213,14 @@ int CopyingInputStream::Skip(int count) {
CopyingInputStreamAdaptor::CopyingInputStreamAdaptor(
CopyingInputStream* copying_stream, int block_size)
: copying_stream_(copying_stream),
owns_copying_stream_(false),
failed_(false),
position_(0),
buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
buffer_used_(0),
backup_bytes_(0) {}
: copying_stream_(copying_stream),
owns_copying_stream_(false),
failed_(false),
position_(0),
buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
buffer_used_(0),
backup_bytes_(0) {
}
CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() {
if (owns_copying_stream_) {
@@ -246,11 +264,12 @@ bool CopyingInputStreamAdaptor::Next(const void** data, int* size) {
void CopyingInputStreamAdaptor::BackUp(int count) {
GOOGLE_CHECK(backup_bytes_ == 0 && buffer_.get() != NULL)
<< " BackUp() can only be called after Next().";
<< " BackUp() can only be called after Next().";
GOOGLE_CHECK_LE(count, buffer_used_)
<< " Can't back up over more bytes than were returned by the last call"
" to Next().";
GOOGLE_CHECK_GE(count, 0) << " Parameter to BackUp() can't be negative.";
<< " Can't back up over more bytes than were returned by the last call"
" to Next().";
GOOGLE_CHECK_GE(count, 0)
<< " Parameter to BackUp() can't be negative.";
backup_bytes_ = count;
}
@@ -278,13 +297,13 @@ bool CopyingInputStreamAdaptor::Skip(int count) {
return skipped == count;
}
int64_t CopyingInputStreamAdaptor::ByteCount() const {
int64 CopyingInputStreamAdaptor::ByteCount() const {
return position_ - backup_bytes_;
}
void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
if (buffer_.get() == NULL) {
buffer_.reset(new uint8_t[buffer_size_]);
buffer_.reset(new uint8[buffer_size_]);
}
}
@@ -298,12 +317,13 @@ void CopyingInputStreamAdaptor::FreeBuffer() {
CopyingOutputStreamAdaptor::CopyingOutputStreamAdaptor(
CopyingOutputStream* copying_stream, int block_size)
: copying_stream_(copying_stream),
owns_copying_stream_(false),
failed_(false),
position_(0),
buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
buffer_used_(0) {}
: copying_stream_(copying_stream),
owns_copying_stream_(false),
failed_(false),
position_(0),
buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
buffer_used_(0) {
}
CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() {
WriteBuffer();
@@ -312,7 +332,9 @@ CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() {
}
}
bool CopyingOutputStreamAdaptor::Flush() { return WriteBuffer(); }
bool CopyingOutputStreamAdaptor::Flush() {
return WriteBuffer();
}
bool CopyingOutputStreamAdaptor::Next(void** data, int* size) {
if (buffer_used_ == buffer_size_) {
@@ -330,49 +352,18 @@ bool CopyingOutputStreamAdaptor::Next(void** data, int* size) {
void CopyingOutputStreamAdaptor::BackUp(int count) {
GOOGLE_CHECK_GE(count, 0);
GOOGLE_CHECK_EQ(buffer_used_, buffer_size_)
<< " BackUp() can only be called after Next().";
<< " BackUp() can only be called after Next().";
GOOGLE_CHECK_LE(count, buffer_used_)
<< " Can't back up over more bytes than were returned by the last call"
" to Next().";
<< " Can't back up over more bytes than were returned by the last call"
" to Next().";
buffer_used_ -= count;
}
int64_t CopyingOutputStreamAdaptor::ByteCount() const {
int64 CopyingOutputStreamAdaptor::ByteCount() const {
return position_ + buffer_used_;
}
bool CopyingOutputStreamAdaptor::WriteAliasedRaw(const void* data, int size) {
if (size >= buffer_size_) {
if (!Flush() || !copying_stream_->Write(data, size)) {
return false;
}
GOOGLE_DCHECK_EQ(buffer_used_, 0);
position_ += size;
return true;
}
void* out;
int out_size;
while (true) {
if (!Next(&out, &out_size)) {
return false;
}
if (size <= out_size) {
std::memcpy(out, data, size);
BackUp(out_size - size);
return true;
}
std::memcpy(out, data, out_size);
data = static_cast<const char*>(data) + out_size;
size -= out_size;
}
return true;
}
bool CopyingOutputStreamAdaptor::WriteBuffer() {
if (failed_) {
// Already failed on a previous write.
@@ -394,7 +385,7 @@ bool CopyingOutputStreamAdaptor::WriteBuffer() {
void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() {
if (buffer_ == NULL) {
buffer_.reset(new uint8_t[buffer_size_]);
buffer_.reset(new uint8[buffer_size_]);
}
}
@@ -403,63 +394,6 @@ void CopyingOutputStreamAdaptor::FreeBuffer() {
buffer_.reset();
}
// ===================================================================
LimitingInputStream::LimitingInputStream(ZeroCopyInputStream* input,
int64_t limit)
: input_(input), limit_(limit) {
prior_bytes_read_ = input_->ByteCount();
}
LimitingInputStream::~LimitingInputStream() {
// If we overshot the limit, back up.
if (limit_ < 0) input_->BackUp(-limit_);
}
bool LimitingInputStream::Next(const void** data, int* size) {
if (limit_ <= 0) return false;
if (!input_->Next(data, size)) return false;
limit_ -= *size;
if (limit_ < 0) {
// We overshot the limit. Reduce *size to hide the rest of the buffer.
*size += limit_;
}
return true;
}
void LimitingInputStream::BackUp(int count) {
if (limit_ < 0) {
input_->BackUp(count - limit_);
limit_ = count;
} else {
input_->BackUp(count);
limit_ += count;
}
}
bool LimitingInputStream::Skip(int count) {
if (count > limit_) {
if (limit_ < 0) return false;
input_->Skip(limit_);
limit_ = 0;
return false;
} else {
if (!input_->Skip(count)) return false;
limit_ -= count;
return true;
}
}
int64_t LimitingInputStream::ByteCount() const {
if (limit_ < 0) {
return input_->ByteCount() + limit_ - prior_bytes_read_;
} else {
return input_->ByteCount() - prior_bytes_read_;
}
}
// ===================================================================
} // namespace io
@@ -44,19 +44,18 @@
#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
#include <iosfwd>
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <string>
#include <iosfwd>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/callback.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/stl_util.h>
#include <google/protobuf/port_def.inc>
namespace google {
namespace protobuf {
namespace io {
@@ -64,7 +63,7 @@ namespace io {
// ===================================================================
// A ZeroCopyInputStream backed by an in-memory array of bytes.
class PROTOBUF_EXPORT ArrayInputStream : public ZeroCopyInputStream {
class LIBPROTOBUF_EXPORT ArrayInputStream : public ZeroCopyInputStream {
public:
// Create an InputStream that returns the bytes pointed to by "data".
// "data" remains the property of the caller but must remain valid until
@@ -74,23 +73,22 @@ class PROTOBUF_EXPORT ArrayInputStream : public ZeroCopyInputStream {
// useful for testing; in production you would probably never want to set
// it.
ArrayInputStream(const void* data, int size, int block_size = -1);
~ArrayInputStream() override = default;
// implements ZeroCopyInputStream ----------------------------------
bool Next(const void** data, int* size) override;
void BackUp(int count) override;
bool Skip(int count) override;
int64_t ByteCount() const override;
bool Next(const void** data, int* size);
void BackUp(int count);
bool Skip(int count);
int64 ByteCount() const;
private:
const uint8_t* const data_; // The byte array.
const uint8* const data_; // The byte array.
const int size_; // Total size of the array.
const int block_size_; // How many bytes to return at a time.
int position_;
int last_returned_size_; // How many bytes we returned last time Next()
// was called (used for error checking only).
int last_returned_size_; // How many bytes we returned last time Next()
// was called (used for error checking only).
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayInputStream);
};
@@ -98,7 +96,7 @@ class PROTOBUF_EXPORT ArrayInputStream : public ZeroCopyInputStream {
// ===================================================================
// A ZeroCopyOutputStream backed by an in-memory array of bytes.
class PROTOBUF_EXPORT ArrayOutputStream : public ZeroCopyOutputStream {
class LIBPROTOBUF_EXPORT ArrayOutputStream : public ZeroCopyOutputStream {
public:
// Create an OutputStream that writes to the bytes pointed to by "data".
// "data" remains the property of the caller but must remain valid until
@@ -108,21 +106,20 @@ class PROTOBUF_EXPORT ArrayOutputStream : public ZeroCopyOutputStream {
// useful for testing; in production you would probably never want to set
// it.
ArrayOutputStream(void* data, int size, int block_size = -1);
~ArrayOutputStream() override = default;
// implements ZeroCopyOutputStream ---------------------------------
bool Next(void** data, int* size) override;
void BackUp(int count) override;
int64_t ByteCount() const override;
bool Next(void** data, int* size);
void BackUp(int count);
int64 ByteCount() const;
private:
uint8_t* const data_; // The byte array.
const int size_; // Total size of the array.
const int block_size_; // How many bytes to return at a time.
uint8* const data_; // The byte array.
const int size_; // Total size of the array.
const int block_size_; // How many bytes to return at a time.
int position_;
int last_returned_size_; // How many bytes we returned last time Next()
// was called (used for error checking only).
int last_returned_size_; // How many bytes we returned last time Next()
// was called (used for error checking only).
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayOutputStream);
};
@@ -130,7 +127,7 @@ class PROTOBUF_EXPORT ArrayOutputStream : public ZeroCopyOutputStream {
// ===================================================================
// A ZeroCopyOutputStream which appends bytes to a string.
class PROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream {
class LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream {
public:
// Create a StringOutputStream which appends bytes to the given string.
// The string remains property of the caller, but it is mutated in arbitrary
@@ -141,18 +138,20 @@ class PROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream {
// Hint: If you call target->reserve(n) before creating the stream,
// the first call to Next() will return at least n bytes of buffer
// space.
explicit StringOutputStream(std::string* target);
~StringOutputStream() override = default;
explicit StringOutputStream(string* target);
// implements ZeroCopyOutputStream ---------------------------------
bool Next(void** data, int* size) override;
void BackUp(int count) override;
int64_t ByteCount() const override;
bool Next(void** data, int* size);
void BackUp(int count);
int64 ByteCount() const;
protected:
void SetString(string* target);
private:
static constexpr size_t kMinimumSize = 16;
static const int kMinimumSize = 16;
std::string* target_;
string* target_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOutputStream);
};
@@ -174,7 +173,7 @@ class PROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream {
// CopyingInputStream implementations should avoid buffering if possible.
// CopyingInputStreamAdaptor does its own buffering and will read data
// in large blocks.
class PROTOBUF_EXPORT CopyingInputStream {
class LIBPROTOBUF_EXPORT CopyingInputStream {
public:
virtual ~CopyingInputStream() {}
@@ -200,7 +199,7 @@ class PROTOBUF_EXPORT CopyingInputStream {
// If you want to read from file descriptors or C++ istreams, this is
// already implemented for you: use FileInputStream or IstreamInputStream
// respectively.
class PROTOBUF_EXPORT CopyingInputStreamAdaptor : public ZeroCopyInputStream {
class LIBPROTOBUF_EXPORT CopyingInputStreamAdaptor : public ZeroCopyInputStream {
public:
// Creates a stream that reads from the given CopyingInputStream.
// If a block_size is given, it specifies the number of bytes that
@@ -209,17 +208,17 @@ class PROTOBUF_EXPORT CopyingInputStreamAdaptor : public ZeroCopyInputStream {
// copying_stream unless SetOwnsCopyingStream(true) is called.
explicit CopyingInputStreamAdaptor(CopyingInputStream* copying_stream,
int block_size = -1);
~CopyingInputStreamAdaptor() override;
~CopyingInputStreamAdaptor();
// Call SetOwnsCopyingStream(true) to tell the CopyingInputStreamAdaptor to
// delete the underlying CopyingInputStream when it is destroyed.
void SetOwnsCopyingStream(bool value) { owns_copying_stream_ = value; }
// implements ZeroCopyInputStream ----------------------------------
bool Next(const void** data, int* size) override;
void BackUp(int count) override;
bool Skip(int count) override;
int64_t ByteCount() const override;
bool Next(const void** data, int* size);
void BackUp(int count);
bool Skip(int count);
int64 ByteCount() const;
private:
// Insures that buffer_ is not NULL.
@@ -231,16 +230,16 @@ class PROTOBUF_EXPORT CopyingInputStreamAdaptor : public ZeroCopyInputStream {
CopyingInputStream* copying_stream_;
bool owns_copying_stream_;
// True if we have seen a permanent error from the underlying stream.
// True if we have seen a permenant error from the underlying stream.
bool failed_;
// The current position of copying_stream_, relative to the point where
// we started reading.
int64_t position_;
int64 position_;
// Data is read into this buffer. It may be NULL if no buffer is currently
// in use. Otherwise, it points to an array of size buffer_size_.
std::unique_ptr<uint8_t[]> buffer_;
google::protobuf::scoped_array<uint8> buffer_;
const int buffer_size_;
// Number of valid bytes currently in the buffer (i.e. the size last
@@ -268,7 +267,7 @@ class PROTOBUF_EXPORT CopyingInputStreamAdaptor : public ZeroCopyInputStream {
// CopyingOutputStream implementations should avoid buffering if possible.
// CopyingOutputStreamAdaptor does its own buffering and will write data
// in large blocks.
class PROTOBUF_EXPORT CopyingOutputStream {
class LIBPROTOBUF_EXPORT CopyingOutputStream {
public:
virtual ~CopyingOutputStream() {}
@@ -284,7 +283,7 @@ class PROTOBUF_EXPORT CopyingOutputStream {
// If you want to write to file descriptors or C++ ostreams, this is
// already implemented for you: use FileOutputStream or OstreamOutputStream
// respectively.
class PROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStream {
class LIBPROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStream {
public:
// Creates a stream that writes to the given Unix file descriptor.
// If a block_size is given, it specifies the size of the buffers
@@ -292,7 +291,7 @@ class PROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStream {
// is used.
explicit CopyingOutputStreamAdaptor(CopyingOutputStream* copying_stream,
int block_size = -1);
~CopyingOutputStreamAdaptor() override;
~CopyingOutputStreamAdaptor();
// Writes all pending data to the underlying stream. Returns false if a
// write error occurred on the underlying stream. (The underlying
@@ -304,11 +303,9 @@ class PROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStream {
void SetOwnsCopyingStream(bool value) { owns_copying_stream_ = value; }
// implements ZeroCopyOutputStream ---------------------------------
bool Next(void** data, int* size) override;
void BackUp(int count) override;
int64_t ByteCount() const override;
bool WriteAliasedRaw(const void* data, int size) override;
bool AllowsAliasing() const override { return true; }
bool Next(void** data, int* size);
void BackUp(int count);
int64 ByteCount() const;
private:
// Write the current buffer, if it is present.
@@ -322,16 +319,16 @@ class PROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStream {
CopyingOutputStream* copying_stream_;
bool owns_copying_stream_;
// True if we have seen a permanent error from the underlying stream.
// True if we have seen a permenant error from the underlying stream.
bool failed_;
// The current position of copying_stream_, relative to the point where
// we started writing.
int64_t position_;
int64 position_;
// Data is written from this buffer. It may be NULL if no buffer is
// currently in use. Otherwise, it points to an array of size buffer_size_.
std::unique_ptr<uint8_t[]> buffer_;
google::protobuf::scoped_array<uint8> buffer_;
const int buffer_size_;
// Number of valid bytes currently in the buffer (i.e. the size last
@@ -342,31 +339,6 @@ class PROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStream {
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingOutputStreamAdaptor);
};
// ===================================================================
// A ZeroCopyInputStream which wraps some other stream and limits it to
// a particular byte count.
class PROTOBUF_EXPORT LimitingInputStream : public ZeroCopyInputStream {
public:
LimitingInputStream(ZeroCopyInputStream* input, int64_t limit);
~LimitingInputStream() override;
// implements ZeroCopyInputStream ----------------------------------
bool Next(const void** data, int* size) override;
void BackUp(int count) override;
bool Skip(int count) override;
int64_t ByteCount() const override;
private:
ZeroCopyInputStream* input_;
int64_t limit_; // Decreases as we go, becomes negative if we overshoot.
int64_t prior_bytes_read_; // Bytes read on underlying stream at construction
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LimitingInputStream);
};
// ===================================================================
// mutable_string_data() and as_string_data() are workarounds to improve
@@ -384,25 +356,31 @@ class PROTOBUF_EXPORT LimitingInputStream : public ZeroCopyInputStream {
// Return a pointer to mutable characters underlying the given string. The
// return value is valid until the next time the string is resized. We
// trust the caller to treat the return value as an array of length s->size().
inline char* mutable_string_data(std::string* s) {
inline char* mutable_string_data(string* s) {
#ifdef LANG_CXX11
// This should be simpler & faster than string_as_array() because the latter
// is guaranteed to return NULL when *s is empty, so it has to check for that.
return &(*s)[0];
#else
return string_as_array(s);
#endif
}
// as_string_data(s) is equivalent to
// ({ char* p = mutable_string_data(s); make_pair(p, p != NULL); })
// Sometimes it's faster: in some scenarios p cannot be NULL, and then the
// code can avoid that check.
inline std::pair<char*, bool> as_string_data(std::string* s) {
char* p = mutable_string_data(s);
inline std::pair<char*, bool> as_string_data(string* s) {
char *p = mutable_string_data(s);
#ifdef LANG_CXX11
return std::make_pair(p, true);
#else
return std::make_pair(p, p != NULL);
#endif
}
} // namespace io
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
File diff suppressed because it is too large Load Diff
+33 -53
View File
@@ -34,16 +34,10 @@
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/map_entry_lite.h>
#include <google/protobuf/map_type_handler.h>
#include <google/protobuf/port.h>
#include <google/protobuf/metadata.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/port_def.inc>
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
#include <google/protobuf/wire_format_lite_inl.h>
namespace google {
namespace protobuf {
@@ -51,13 +45,11 @@ class Arena;
namespace internal {
template <typename Derived, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
class MapField;
}
} // namespace protobuf
} // namespace google
}
namespace google {
namespace protobuf {
namespace internal {
@@ -78,52 +70,40 @@ namespace internal {
// field.
//
// cpp type | proto type | in-memory type | MapEntry accessor type
// int32_t TYPE_INT32 int32_t int32_t
// int32_t TYPE_FIXED32 int32_t int32_t
// int32 TYPE_INT32 int32 int32
// int32 TYPE_FIXED32 int32 int32
// string TYPE_STRING ArenaStringPtr string
// FooEnum TYPE_ENUM int int
// FooMessage TYPE_MESSAGE FooMessage* FooMessage
//
// The in-memory types of primitive types can be inferred from its proto type,
// while we need to explicitly specify the cpp type if proto type is
// TYPE_MESSAGE to infer the in-memory type.
// TYPE_MESSAGE to infer the in-memory type. Moreover, default_enum_value is
// used to initialize enum field in proto2.
template <typename Derived, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
class MapEntry : public MapEntryImpl<Derived, Message, Key, Value,
kKeyFieldType, kValueFieldType> {
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
class MapEntry
: public MapEntryImpl<Derived, Message, Key, Value, kKeyFieldType,
kValueFieldType, default_enum_value> {
public:
constexpr MapEntry() : _internal_metadata_() {}
MapEntry() : _internal_metadata_(NULL) {}
explicit MapEntry(Arena* arena)
: MapEntryImpl<Derived, Message, Key, Value, kKeyFieldType,
kValueFieldType>(arena),
kValueFieldType, default_enum_value>(arena),
_internal_metadata_(arena) {}
~MapEntry() {
Message::_internal_metadata_.template Delete<UnknownFieldSet>();
_internal_metadata_.Delete<UnknownFieldSet>();
}
typedef void InternalArenaConstructable_;
typedef void DestructorSkippable_;
typedef typename MapEntryImpl<Derived, Message, Key, Value, kKeyFieldType,
kValueFieldType>::KeyTypeHandler KeyTypeHandler;
typedef
typename MapEntryImpl<Derived, Message, Key, Value, kKeyFieldType,
kValueFieldType>::ValueTypeHandler ValueTypeHandler;
size_t SpaceUsedLong() const override {
size_t size = sizeof(Derived);
size += KeyTypeHandler::SpaceUsedInMapEntryLong(this->key_);
size += ValueTypeHandler::SpaceUsedInMapEntryLong(this->value_);
return size;
}
InternalMetadata _internal_metadata_;
InternalMetadataWithArena _internal_metadata_;
private:
friend class ::PROTOBUF_NAMESPACE_ID::Arena;
friend class ::google::protobuf::Arena;
template <typename C, typename K, typename V,
WireFormatLite::FieldType k_wire_type, WireFormatLite::FieldType>
WireFormatLite::FieldType k_wire_type, WireFormatLite::FieldType,
int default_enum>
friend class internal::MapField;
friend class internal::GeneratedMessageReflection;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntry);
};
@@ -131,30 +111,30 @@ class MapEntry : public MapEntryImpl<Derived, Message, Key, Value,
// Specialization for the full runtime
template <typename Derived, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
struct MapEntryHelper<
MapEntry<Derived, Key, Value, kKeyFieldType, kValueFieldType> >
: MapEntryHelper<
MapEntryLite<Derived, Key, Value, kKeyFieldType, kValueFieldType> > {
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
struct MapEntryHelper<MapEntry<Derived, Key, Value, kKeyFieldType,
kValueFieldType, default_enum_value> >
: MapEntryHelper<MapEntryLite<Derived, Key, Value, kKeyFieldType,
kValueFieldType, default_enum_value> > {
explicit MapEntryHelper(const MapPair<Key, Value>& map_pair)
: MapEntryHelper<
MapEntryLite<Derived, Key, Value, kKeyFieldType, kValueFieldType> >(
: MapEntryHelper<MapEntryLite<Derived, Key, Value, kKeyFieldType,
kValueFieldType, default_enum_value> >(
map_pair) {}
};
template <typename Derived, typename K, typename V,
WireFormatLite::FieldType key, WireFormatLite::FieldType value>
struct DeconstructMapEntry<MapEntry<Derived, K, V, key, value> > {
WireFormatLite::FieldType key, WireFormatLite::FieldType value,
int default_enum>
struct DeconstructMapEntry<MapEntry<Derived, K, V, key, value, default_enum> > {
typedef K Key;
typedef V Value;
static constexpr WireFormatLite::FieldType kKeyFieldType = key;
static constexpr WireFormatLite::FieldType kValueFieldType = value;
static const WireFormatLite::FieldType kKeyFieldType = key;
static const WireFormatLite::FieldType kValueFieldType = value;
static const int default_enum_value = default_enum;
};
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_MAP_ENTRY_H__
+272 -260
View File
@@ -32,40 +32,27 @@
#define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
#include <assert.h>
#include <string>
#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/parse_context.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/map.h>
#include <google/protobuf/map_type_handler.h>
#include <google/protobuf/port.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/port_def.inc>
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/wire_format_lite_inl.h>
namespace google {
namespace protobuf {
namespace internal {
template <typename Derived, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
class MapEntry;
template <typename Derived, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
class MapFieldLite;
} // namespace internal
} // namespace protobuf
} // namespace google
namespace google {
namespace protobuf {
namespace internal {
@@ -93,45 +80,11 @@ struct MoveHelper<false, true, is_stringlike, T> { // messages
template <typename T>
struct MoveHelper<false, false, true, T> { // strings and similar
static void Move(T* src, T* dest) {
#if __cplusplus >= 201103L
*dest = std::move(*src);
}
};
// Functions for operating on a map entry. Does not contain any representation
// (this class is not intended to be instantiated).
template <typename Key, typename Value, WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
struct MapEntryFuncs {
typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler;
static const int kKeyFieldNumber = 1;
static const int kValueFieldNumber = 2;
static uint8_t* InternalSerialize(int field_number, const Key& key,
const Value& value, uint8_t* ptr,
io::EpsCopyOutputStream* stream) {
ptr = stream->EnsureSpace(ptr);
ptr = WireFormatLite::WriteTagToArray(
field_number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, ptr);
ptr = io::CodedOutputStream::WriteVarint32ToArray(GetCachedSize(key, value),
ptr);
ptr = KeyTypeHandler::Write(kKeyFieldNumber, key, ptr, stream);
return ValueTypeHandler::Write(kValueFieldNumber, value, ptr, stream);
}
static size_t ByteSizeLong(const Key& key, const Value& value) {
// Tags for key and value will both be one byte (field numbers 1 and 2).
size_t inner_length =
2 + KeyTypeHandler::ByteSize(key) + ValueTypeHandler::ByteSize(value);
return inner_length + io::CodedOutputStream::VarintSize32(
static_cast<uint32_t>(inner_length));
}
static int GetCachedSize(const Key& key, const Value& value) {
// Tags for key and value will both be one byte (field numbers 1 and 2).
return 2 + KeyTypeHandler::GetCachedSize(key) +
ValueTypeHandler::GetCachedSize(value);
#else
dest->swap(*src);
#endif
}
};
@@ -140,11 +93,8 @@ struct MapEntryFuncs {
// the eventual code to the template code.
template <typename Derived, typename Base, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
class MapEntryImpl : public Base {
public:
typedef MapEntryFuncs<Key, Value, kKeyFieldType, kValueFieldType> Funcs;
protected:
// Provide utilities to parse/serialize key/value. Provide utilities to
// manipulate internal stored type.
@@ -159,17 +109,17 @@ class MapEntryImpl : public Base {
// Enum type cannot be used for MapTypeHandler::Read. Define a type
// which will replace Enum with int.
typedef typename KeyTypeHandler::MapEntryAccessorType KeyMapEntryAccessorType;
typedef
typename ValueTypeHandler::MapEntryAccessorType ValueMapEntryAccessorType;
typedef typename ValueTypeHandler::MapEntryAccessorType
ValueMapEntryAccessorType;
// Constants for field number.
static const int kKeyFieldNumber = 1;
static const int kValueFieldNumber = 2;
// Constants for field tag.
static const uint8_t kKeyTag =
GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kKeyFieldNumber, KeyTypeHandler::kWireType);
static const uint8_t kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
static const uint8 kKeyTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
kKeyFieldNumber, KeyTypeHandler::kWireType);
static const uint8 kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
kValueFieldNumber, ValueTypeHandler::kWireType);
static const size_t kTagSize = 1;
@@ -181,20 +131,24 @@ class MapEntryImpl : public Base {
typedef Value EntryValueType;
static const WireFormatLite::FieldType kEntryKeyFieldType = kKeyFieldType;
static const WireFormatLite::FieldType kEntryValueFieldType = kValueFieldType;
static const int kEntryDefaultEnumValue = default_enum_value;
constexpr MapEntryImpl()
: key_(KeyTypeHandler::Constinit()),
value_(ValueTypeHandler::Constinit()),
_has_bits_{} {}
MapEntryImpl() : arena_(NULL) {
KeyTypeHandler::Initialize(&key_, NULL);
ValueTypeHandler::InitializeMaybeByDefaultEnum(&value_, default_enum_value,
NULL);
_has_bits_[0] = 0;
}
explicit MapEntryImpl(Arena* arena)
: Base(arena),
key_(KeyTypeHandler::Constinit()),
value_(ValueTypeHandler::Constinit()),
_has_bits_{} {}
explicit MapEntryImpl(Arena* arena) : arena_(arena) {
KeyTypeHandler::Initialize(&key_, arena);
ValueTypeHandler::InitializeMaybeByDefaultEnum(&value_, default_enum_value,
arena);
_has_bits_[0] = 0;
}
~MapEntryImpl() {
if (Base::GetArenaForAllocation() != nullptr) return;
if (GetArenaNoVirtual() != NULL) return;
KeyTypeHandler::DeleteNoArena(key_);
ValueTypeHandler::DeleteNoArena(value_);
}
@@ -205,134 +159,187 @@ class MapEntryImpl : public Base {
return KeyTypeHandler::GetExternalReference(key_);
}
virtual inline const ValueMapEntryAccessorType& value() const {
return ValueTypeHandler::DefaultIfNotInitialized(value_);
return ValueTypeHandler::DefaultIfNotInitialized(
value_, Derived::internal_default_instance()->value_);
}
inline KeyMapEntryAccessorType* mutable_key() {
set_has_key();
return KeyTypeHandler::EnsureMutable(&key_, Base::GetArenaForAllocation());
return KeyTypeHandler::EnsureMutable(&key_, GetArenaNoVirtual());
}
inline ValueMapEntryAccessorType* mutable_value() {
set_has_value();
return ValueTypeHandler::EnsureMutable(&value_,
Base::GetArenaForAllocation());
return ValueTypeHandler::EnsureMutable(&value_, GetArenaNoVirtual());
}
// implements MessageLite =========================================
// MapEntryImpl is for implementation only and this function isn't called
// anywhere. Just provide a fake implementation here for MessageLite.
std::string GetTypeName() const override { return ""; }
string GetTypeName() const { return ""; }
void CheckTypeAndMergeFrom(const MessageLite& other) override {
MergeFromInternal(*::google::protobuf::internal::DownCast<const Derived*>(&other));
void CheckTypeAndMergeFrom(const MessageLite& other) {
MergeFromInternal(*::google::protobuf::down_cast<const Derived*>(&other));
}
const char* _InternalParse(const char* ptr, ParseContext* ctx) final {
while (!ctx->Done(&ptr)) {
uint32_t tag;
ptr = ReadTag(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
if (tag == kKeyTag) {
set_has_key();
KeyMapEntryAccessorType* key = mutable_key();
ptr = KeyTypeHandler::Read(ptr, ctx, key);
if (!Derived::ValidateKey(key)) return nullptr;
} else if (tag == kValueTag) {
set_has_value();
ValueMapEntryAccessorType* value = mutable_value();
ptr = ValueTypeHandler::Read(ptr, ctx, value);
if (!Derived::ValidateValue(value)) return nullptr;
} else {
if (tag == 0 || WireFormatLite::GetTagWireType(tag) ==
WireFormatLite::WIRETYPE_END_GROUP) {
ctx->SetLastTag(tag);
return ptr;
}
ptr = UnknownFieldParse(tag, static_cast<std::string*>(nullptr), ptr,
ctx);
bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream* input) {
uint32 tag;
for (;;) {
// 1) corrupted data: return false;
// 2) unknown field: skip without putting into unknown field set;
// 3) unknown enum value: keep it in parsing. In proto2, caller should
// check the value and put this entry into containing message's unknown
// field set if the value is an unknown enum. In proto3, caller doesn't
// need to care whether the value is unknown enum;
// 4) missing key/value: missed key/value will have default value. caller
// should take this entry as if key/value is set to default value.
tag = input->ReadTagNoLastTag();
switch (tag) {
case kKeyTag:
if (!KeyTypeHandler::Read(input, mutable_key())) {
return false;
}
set_has_key();
if (!input->ExpectTag(kValueTag)) break;
GOOGLE_FALLTHROUGH_INTENDED;
case kValueTag:
if (!ValueTypeHandler::Read(input, mutable_value())) {
return false;
}
set_has_value();
if (input->ExpectAtEnd()) return true;
break;
default:
if (tag == 0 ||
WireFormatLite::GetTagWireType(tag) ==
WireFormatLite::WIRETYPE_END_GROUP) {
return true;
}
if (!WireFormatLite::SkipField(input, tag)) return false;
break;
}
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
}
return ptr;
}
size_t ByteSizeLong() const override {
size_t ByteSizeLong() const {
size_t size = 0;
size += kTagSize + static_cast<size_t>(KeyTypeHandler::ByteSize(key()));
size += kTagSize + static_cast<size_t>(ValueTypeHandler::ByteSize(value()));
size += has_key() ?
kTagSize + static_cast<size_t>(KeyTypeHandler::ByteSize(key())) : 0;
size += has_value() ?
kTagSize + static_cast<size_t>(ValueTypeHandler::ByteSize(value())) : 0;
return size;
}
::uint8_t* _InternalSerialize(
::uint8_t* ptr, io::EpsCopyOutputStream* stream) const override {
ptr = KeyTypeHandler::Write(kKeyFieldNumber, key(), ptr, stream);
return ValueTypeHandler::Write(kValueFieldNumber, value(), ptr, stream);
void SerializeWithCachedSizes(::google::protobuf::io::CodedOutputStream* output) const {
KeyTypeHandler::Write(kKeyFieldNumber, key(), output);
ValueTypeHandler::Write(kValueFieldNumber, value(), output);
}
::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(bool deterministic,
::google::protobuf::uint8* output) const {
output = KeyTypeHandler::InternalWriteToArray(kKeyFieldNumber, key(),
deterministic, output);
output = ValueTypeHandler::InternalWriteToArray(kValueFieldNumber, value(),
deterministic, output);
return output;
}
// Don't override SerializeWithCachedSizesToArray. Use MessageLite's.
int GetCachedSize() const override {
int GetCachedSize() const {
int size = 0;
size += has_key() ? static_cast<int>(kTagSize) +
KeyTypeHandler::GetCachedSize(key())
: 0;
size += has_value() ? static_cast<int>(kTagSize) +
ValueTypeHandler::GetCachedSize(value())
: 0;
size += has_key()
? static_cast<int>(kTagSize) + KeyTypeHandler::GetCachedSize(key())
: 0;
size += has_value()
? static_cast<int>(kTagSize) + ValueTypeHandler::GetCachedSize(value())
: 0;
return size;
}
bool IsInitialized() const override {
return ValueTypeHandler::IsInitialized(value_);
bool IsInitialized() const { return ValueTypeHandler::IsInitialized(value_); }
Base* New() const {
Derived* entry = new Derived;
return entry;
}
Base* New(Arena* arena) const override {
Base* New(Arena* arena) const {
Derived* entry = Arena::CreateMessage<Derived>(arena);
return entry;
}
size_t SpaceUsedLong() const {
size_t size = sizeof(Derived);
size += KeyTypeHandler::SpaceUsedInMapEntryLong(key_);
size += ValueTypeHandler::SpaceUsedInMapEntryLong(value_);
return size;
}
protected:
// We can't declare this function directly here as it would hide the other
// overload (const Message&).
void MergeFromInternal(const MapEntryImpl& from) {
if (from._has_bits_[0]) {
if (from.has_key()) {
KeyTypeHandler::EnsureMutable(&key_, Base::GetArenaForAllocation());
KeyTypeHandler::Merge(from.key(), &key_, Base::GetArenaForAllocation());
KeyTypeHandler::EnsureMutable(&key_, GetArenaNoVirtual());
KeyTypeHandler::Merge(from.key(), &key_, GetArenaNoVirtual());
set_has_key();
}
if (from.has_value()) {
ValueTypeHandler::EnsureMutable(&value_, Base::GetArenaForAllocation());
ValueTypeHandler::Merge(from.value(), &value_,
Base::GetArenaForAllocation());
ValueTypeHandler::EnsureMutable(&value_, GetArenaNoVirtual());
ValueTypeHandler::Merge(from.value(), &value_, GetArenaNoVirtual());
set_has_value();
}
}
}
public:
void Clear() override {
KeyTypeHandler::Clear(&key_, Base::GetArenaForAllocation());
ValueTypeHandler::Clear(&value_, Base::GetArenaForAllocation());
void Clear() {
KeyTypeHandler::Clear(&key_, GetArenaNoVirtual());
ValueTypeHandler::ClearMaybeByDefaultEnum(
&value_, GetArenaNoVirtual(), default_enum_value);
clear_has_key();
clear_has_value();
}
static void InitAsDefaultInstance() {
Derived* d = const_cast<Derived*>(Derived::internal_default_instance());
KeyTypeHandler::AssignDefaultValue(&d->key_);
ValueTypeHandler::AssignDefaultValue(&d->value_);
}
Arena* GetArena() const {
return GetArenaNoVirtual();
}
// Create a MapEntryImpl for given key and value from google::protobuf::Map in
// serialization. This function is only called when value is enum. Enum is
// treated differently because its type in MapEntry is int and its type in
// google::protobuf::Map is enum. We cannot create a reference to int from an enum.
static Derived* EnumWrap(const Key& key, const Value value, Arena* arena) {
return Arena::CreateMessage<MapEnumEntryWrapper>(arena, key, value);
}
// Like above, but for all the other types. This avoids value copy to create
// MapEntryImpl from google::protobuf::Map in serialization.
static Derived* Wrap(const Key& key, const Value& value, Arena* arena) {
return Arena::CreateMessage<MapEntryWrapper>(arena, key, value);
}
// Parsing using MergePartialFromCodedStream, above, is not as
// efficient as it could be. This helper class provides a speedier way.
template <typename MapField, typename Map>
class Parser {
public:
explicit Parser(MapField* mf) : mf_(mf), map_(mf->MutableMap()) {}
~Parser() {
if (entry_ != nullptr && entry_->GetArenaForAllocation() == nullptr)
delete entry_;
}
// This does what the typical MergePartialFromCodedStream() is expected to
// do, with the additional side-effect that if successful (i.e., if true is
// going to be its return value) it inserts the key-value pair into map_.
bool MergePartialFromCodedStream(io::CodedInputStream* input) {
bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream* input) {
// Look for the expected thing: a key and then a value. If it fails,
// invoke the enclosing class's MergePartialFromCodedStream, or return
// false if that would be pointless.
@@ -345,11 +352,11 @@ class MapEntryImpl : public Base {
int size;
input->GetDirectBufferPointerInline(&data, &size);
// We could use memcmp here, but we don't bother. The tag is one byte.
static_assert(kTagSize == 1, "tag size must be 1");
GOOGLE_COMPILE_ASSERT(kTagSize == 1, tag_size_error);
if (size > 0 && *reinterpret_cast<const char*>(data) == kValueTag) {
typename Map::size_type map_size = map_->size();
typename Map::size_type size = map_->size();
value_ptr_ = &(*map_)[key_];
if (PROTOBUF_PREDICT_TRUE(map_size != map_->size())) {
if (GOOGLE_PREDICT_TRUE(size != map_->size())) {
// We created a new key-value pair. Fill in the value.
typedef
typename MapIf<ValueTypeHandler::kIsEnum, int*, Value*>::type T;
@@ -367,119 +374,64 @@ class MapEntryImpl : public Base {
key_ = Key();
}
NewEntry();
entry_.reset(mf_->NewEntry());
*entry_->mutable_key() = key_;
const bool result = entry_->MergePartialFromCodedStream(input);
if (result) UseKeyAndValueFromEntry();
if (entry_->GetArena() != NULL) entry_.release();
return result;
}
const char* _InternalParse(const char* ptr, ParseContext* ctx) {
if (PROTOBUF_PREDICT_TRUE(!ctx->Done(&ptr) && *ptr == kKeyTag)) {
ptr = KeyTypeHandler::Read(ptr + 1, ctx, &key_);
if (PROTOBUF_PREDICT_FALSE(!ptr || !Derived::ValidateKey(&key_))) {
return nullptr;
}
if (PROTOBUF_PREDICT_TRUE(!ctx->Done(&ptr) && *ptr == kValueTag)) {
typename Map::size_type map_size = map_->size();
value_ptr_ = &(*map_)[key_];
if (PROTOBUF_PREDICT_TRUE(map_size != map_->size())) {
using T =
typename MapIf<ValueTypeHandler::kIsEnum, int*, Value*>::type;
ptr = ValueTypeHandler::Read(ptr + 1, ctx,
reinterpret_cast<T>(value_ptr_));
if (PROTOBUF_PREDICT_FALSE(!ptr ||
!Derived::ValidateValue(value_ptr_))) {
map_->erase(key_); // Failure! Undo insertion.
return nullptr;
}
if (PROTOBUF_PREDICT_TRUE(ctx->Done(&ptr))) return ptr;
if (!ptr) return nullptr;
NewEntry();
ValueMover::Move(value_ptr_, entry_->mutable_value());
map_->erase(key_);
goto move_key;
}
} else {
if (!ptr) return nullptr;
}
NewEntry();
move_key:
KeyMover::Move(&key_, entry_->mutable_key());
} else {
if (!ptr) return nullptr;
NewEntry();
}
ptr = entry_->_InternalParse(ptr, ctx);
if (ptr) UseKeyAndValueFromEntry();
return ptr;
}
template <typename UnknownType>
const char* ParseWithEnumValidation(const char* ptr, ParseContext* ctx,
bool (*is_valid)(int),
uint32_t field_num,
InternalMetadata* metadata) {
auto entry = NewEntry();
ptr = entry->_InternalParse(ptr, ctx);
if (!ptr) return nullptr;
if (is_valid(entry->value())) {
UseKeyAndValueFromEntry();
} else {
WriteLengthDelimited(field_num, entry->SerializeAsString(),
metadata->mutable_unknown_fields<UnknownType>());
}
return ptr;
}
MapEntryImpl* NewEntry() { return entry_ = mf_->NewEntry(); }
const Key& key() const { return key_; }
const Value& value() const { return *value_ptr_; }
const Key& entry_key() const { return entry_->key(); }
const Value& entry_value() const { return entry_->value(); }
private:
void UseKeyAndValueFromEntry() {
void UseKeyAndValueFromEntry() GOOGLE_PROTOBUF_ATTRIBUTE_COLD {
// Update key_ in case we need it later (because key() is called).
// This is potentially inefficient, especially if the key is
// expensive to copy (e.g., a long string), but this is a cold
// path, so it's not a big deal.
key_ = entry_->key();
value_ptr_ = &(*map_)[key_];
ValueMover::Move(entry_->mutable_value(), value_ptr_);
MoveHelper<ValueTypeHandler::kIsEnum,
ValueTypeHandler::kIsMessage,
ValueTypeHandler::kWireType ==
WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
Value>::Move(entry_->mutable_value(), value_ptr_);
}
// After reading a key and value successfully, and inserting that data
// into map_, we are not at the end of the input. This is unusual, but
// allowed by the spec.
bool ReadBeyondKeyValuePair(io::CodedInputStream* input) PROTOBUF_COLD {
NewEntry();
bool ReadBeyondKeyValuePair(::google::protobuf::io::CodedInputStream* input)
GOOGLE_PROTOBUF_ATTRIBUTE_COLD {
typedef MoveHelper<KeyTypeHandler::kIsEnum,
KeyTypeHandler::kIsMessage,
KeyTypeHandler::kWireType ==
WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
Key> KeyMover;
typedef MoveHelper<ValueTypeHandler::kIsEnum,
ValueTypeHandler::kIsMessage,
ValueTypeHandler::kWireType ==
WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
Value> ValueMover;
entry_.reset(mf_->NewEntry());
ValueMover::Move(value_ptr_, entry_->mutable_value());
map_->erase(key_);
KeyMover::Move(&key_, entry_->mutable_key());
const bool result = entry_->MergePartialFromCodedStream(input);
if (result) UseKeyAndValueFromEntry();
if (entry_->GetArena() != NULL) entry_.release();
return result;
}
typedef MoveHelper<KeyTypeHandler::kIsEnum, KeyTypeHandler::kIsMessage,
KeyTypeHandler::kWireType ==
WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
Key>
KeyMover;
typedef MoveHelper<ValueTypeHandler::kIsEnum, ValueTypeHandler::kIsMessage,
ValueTypeHandler::kWireType ==
WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
Value>
ValueMover;
MapField* const mf_;
Map* const map_;
Key key_;
Value* value_ptr_;
MapEntryImpl* entry_ = nullptr;
// On the fast path entry_ is not used. And, when entry_ is used, it's set
// to mf_->NewEntry(), so in the arena case we must call entry_.release.
google::protobuf::scoped_ptr<MapEntryImpl> entry_;
};
protected:
@@ -490,23 +442,89 @@ class MapEntryImpl : public Base {
bool has_value() const { return (_has_bits_[0] & 0x00000002u) != 0; }
void clear_has_value() { _has_bits_[0] &= ~0x00000002u; }
public:
inline Arena* GetArena() const { return Base::GetArena(); }
private:
// Serializing a generated message containing map field involves serializing
// key-value pairs from google::protobuf::Map. The wire format of each key-value pair
// after serialization should be the same as that of a MapEntry message
// containing the same key and value inside it. However, google::protobuf::Map doesn't
// store key and value as MapEntry message, which disables us to use existing
// code to serialize message. In order to use existing code to serialize
// message, we need to construct a MapEntry from key-value pair. But it
// involves copy of key and value to construct a MapEntry. In order to avoid
// this copy in constructing a MapEntry, we need the following class which
// only takes references of given key and value.
class MapEntryWrapper : public Derived {
typedef Derived BaseClass;
typedef typename BaseClass::KeyMapEntryAccessorType KeyMapEntryAccessorType;
typedef
typename BaseClass::ValueMapEntryAccessorType ValueMapEntryAccessorType;
public:
MapEntryWrapper(Arena* arena, const Key& key, const Value& value)
: Derived(arena), key_(key), value_(value) {
BaseClass::set_has_key();
BaseClass::set_has_value();
}
inline const KeyMapEntryAccessorType& key() const { return key_; }
inline const ValueMapEntryAccessorType& value() const { return value_; }
private:
const Key& key_;
const Value& value_;
friend class ::google::protobuf::Arena;
typedef void InternalArenaConstructable_;
typedef void DestructorSkippable_;
};
// Like above, but for enum value only, which stores value instead of
// reference of value field inside. This is needed because the type of value
// field in constructor is an enum, while we need to store it as an int. If we
// initialize a reference to int with a reference to enum, compiler will
// generate a temporary int from enum and initialize the reference to int with
// the temporary.
class MapEnumEntryWrapper : public Derived {
typedef Derived BaseClass;
typedef typename BaseClass::KeyMapEntryAccessorType KeyMapEntryAccessorType;
typedef
typename BaseClass::ValueMapEntryAccessorType ValueMapEntryAccessorType;
public:
MapEnumEntryWrapper(Arena* arena, const Key& key, const Value& value)
: Derived(arena), key_(key), value_(value) {
BaseClass::set_has_key();
BaseClass::set_has_value();
}
inline const KeyMapEntryAccessorType& key() const { return key_; }
inline const ValueMapEntryAccessorType& value() const { return value_; }
private:
const KeyMapEntryAccessorType& key_;
const ValueMapEntryAccessorType value_;
friend class google::protobuf::Arena;
typedef void DestructorSkippable_;
};
inline Arena* GetArenaNoVirtual() const {
return arena_;
}
public: // Needed for constructing tables
KeyOnMemory key_;
ValueOnMemory value_;
uint32_t _has_bits_[1];
Arena* arena_;
uint32 _has_bits_[1];
private:
friend class ::PROTOBUF_NAMESPACE_ID::Arena;
friend class ::google::protobuf::Arena;
typedef void InternalArenaConstructable_;
typedef void DestructorSkippable_;
template <typename C, typename K, typename V, WireFormatLite::FieldType,
WireFormatLite::FieldType>
WireFormatLite::FieldType, int>
friend class internal::MapEntry;
template <typename C, typename K, typename V, WireFormatLite::FieldType,
WireFormatLite::FieldType>
WireFormatLite::FieldType, int>
friend class internal::MapFieldLite;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryImpl);
@@ -514,18 +532,16 @@ class MapEntryImpl : public Base {
template <typename T, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
class MapEntryLite : public MapEntryImpl<T, MessageLite, Key, Value,
kKeyFieldType, kValueFieldType> {
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
class MapEntryLite
: public MapEntryImpl<T, MessageLite, Key, Value, kKeyFieldType,
kValueFieldType, default_enum_value> {
public:
typedef MapEntryImpl<T, MessageLite, Key, Value, kKeyFieldType,
kValueFieldType>
kValueFieldType, default_enum_value>
SuperType;
constexpr MapEntryLite() {}
MapEntryLite() {}
explicit MapEntryLite(Arena* arena) : SuperType(arena) {}
~MapEntryLite() {
MessageLite::_internal_metadata_.template Delete<std::string>();
}
void MergeFrom(const MapEntryLite& other) { MergeFromInternal(other); }
private:
@@ -538,12 +554,13 @@ template <typename Derived>
struct DeconstructMapEntry;
template <typename T, typename K, typename V, WireFormatLite::FieldType key,
WireFormatLite::FieldType value>
struct DeconstructMapEntry<MapEntryLite<T, K, V, key, value> > {
WireFormatLite::FieldType value, int default_enum>
struct DeconstructMapEntry<MapEntryLite<T, K, V, key, value, default_enum> > {
typedef K Key;
typedef V Value;
static const WireFormatLite::FieldType kKeyFieldType = key;
static const WireFormatLite::FieldType kValueFieldType = value;
static const int default_enum_value = default_enum;
};
// Helpers for deterministic serialization =============================
@@ -552,8 +569,7 @@ struct DeconstructMapEntry<MapEntryLite<T, K, V, key, value> > {
// type is relatively small and easy to copy then copying Keys into an
// array of SortItems can be beneficial. Then all the data the sorting
// algorithm needs to touch is in that one array.
template <typename Key, typename PtrToKeyValuePair>
struct SortItem {
template <typename Key, typename PtrToKeyValuePair> struct SortItem {
SortItem() {}
explicit SortItem(PtrToKeyValuePair p) : first(p->first), second(p) {}
@@ -561,14 +577,16 @@ struct SortItem {
PtrToKeyValuePair second;
};
template <typename T>
struct CompareByFirstField {
bool operator()(const T& a, const T& b) const { return a.first < b.first; }
template <typename T> struct CompareByFirstField {
bool operator()(const T& a, const T& b) const {
return a.first < b.first;
}
};
template <typename T>
struct CompareByDerefFirst {
bool operator()(const T& a, const T& b) const { return a->first < b->first; }
template <typename T> struct CompareByDerefFirst {
bool operator()(const T& a, const T& b) const {
return a->first < b->first;
}
};
// Helper for table driven serialization
@@ -583,21 +601,17 @@ struct FromHelper {
template <>
struct FromHelper<WireFormatLite::TYPE_STRING> {
static ArenaStringPtr From(const std::string& x) {
static ArenaStringPtr From(const string& x) {
ArenaStringPtr res;
TaggedPtr<std::string> ptr;
ptr.Set(const_cast<std::string*>(&x));
res.UnsafeSetTaggedPointer(ptr);
*res.UnsafeRawStringPointer() = const_cast<string*>(&x);
return res;
}
};
template <>
struct FromHelper<WireFormatLite::TYPE_BYTES> {
static ArenaStringPtr From(const std::string& x) {
static ArenaStringPtr From(const string& x) {
ArenaStringPtr res;
TaggedPtr<std::string> ptr;
ptr.Set(const_cast<std::string*>(&x));
res.UnsafeSetTaggedPointer(ptr);
*res.UnsafeRawStringPointer() = const_cast<string*>(&x);
return res;
}
};
@@ -614,9 +628,9 @@ struct MapEntryHelper;
template <typename T, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
struct MapEntryHelper<
MapEntryLite<T, Key, Value, kKeyFieldType, kValueFieldType> > {
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
struct MapEntryHelper<MapEntryLite<T, Key, Value, kKeyFieldType,
kValueFieldType, default_enum_value> > {
// Provide utilities to parse/serialize key/value. Provide utilities to
// manipulate internal stored type.
typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
@@ -634,21 +648,19 @@ struct MapEntryHelper<
key_(FromHelper<kKeyFieldType>::From(map_pair.first)),
value_(FromHelper<kValueFieldType>::From(map_pair.second)) {}
// Purposely not following the style guide naming. These are the names
// Purposely not folowing the style guide naming. These are the names
// the proto compiler would generate given the map entry descriptor.
// The proto compiler generates the offsets in this struct as if this was
// a regular message. This way the table driven code barely notices it's
// dealing with a map field.
uint32_t _has_bits_; // NOLINT
uint32_t _cached_size_; // NOLINT
uint32 _has_bits_; // NOLINT
uint32 _cached_size_; // NOLINT
KeyOnMemory key_; // NOLINT
ValueOnMemory value_; // NOLINT
};
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
+165 -358
View File
@@ -33,91 +33,34 @@
#include <vector>
#include <google/protobuf/port_def.inc>
namespace google {
namespace protobuf {
namespace internal {
MapFieldBase::~MapFieldBase() {
if (repeated_field_ != nullptr && arena_ == nullptr) delete repeated_field_;
if (repeated_field_ != NULL && arena_ == NULL) delete repeated_field_;
}
const RepeatedPtrFieldBase& MapFieldBase::GetRepeatedField() const {
ConstAccess();
SyncRepeatedFieldWithMap();
return *reinterpret_cast<RepeatedPtrFieldBase*>(repeated_field_);
return *repeated_field_;
}
RepeatedPtrFieldBase* MapFieldBase::MutableRepeatedField() {
MutableAccess();
SyncRepeatedFieldWithMap();
SetRepeatedDirty();
return reinterpret_cast<RepeatedPtrFieldBase*>(repeated_field_);
}
void MapFieldBase::SwapState(MapFieldBase* other) {
// a relaxed swap of the atomic
auto other_state = other->state_.load(std::memory_order_relaxed);
auto this_state = state_.load(std::memory_order_relaxed);
other->state_.store(this_state, std::memory_order_relaxed);
state_.store(other_state, std::memory_order_relaxed);
}
void SwapRepeatedPtrToNull(RepeatedPtrField<Message>** from,
RepeatedPtrField<Message>** to, Arena* from_arena,
Arena* to_arena) {
GOOGLE_DCHECK(*from != nullptr);
GOOGLE_DCHECK(*to == nullptr);
*to = Arena::CreateMessage<RepeatedPtrField<Message> >(to_arena);
**to = std::move(**from);
if (from_arena == nullptr) {
delete *from;
}
*from = nullptr;
}
void MapFieldBase::Swap(MapFieldBase* other) {
if (arena_ == other->arena_) {
InternalSwap(other);
return;
}
if (repeated_field_ != nullptr || other->repeated_field_ != nullptr) {
if (repeated_field_ == nullptr) {
SwapRepeatedPtrToNull(&other->repeated_field_, &repeated_field_,
other->arena_, arena_);
} else if (other->repeated_field_ == nullptr) {
SwapRepeatedPtrToNull(&repeated_field_, &other->repeated_field_, arena_,
other->arena_);
} else {
repeated_field_->Swap(other->repeated_field_);
}
}
SwapState(other);
}
void MapFieldBase::UnsafeShallowSwap(MapFieldBase* other) {
GOOGLE_DCHECK_EQ(arena_, other->arena_);
InternalSwap(other);
}
void MapFieldBase::InternalSwap(MapFieldBase* other) {
std::swap(arena_, other->arena_);
std::swap(repeated_field_, other->repeated_field_);
SwapState(other);
return repeated_field_;
}
size_t MapFieldBase::SpaceUsedExcludingSelfLong() const {
ConstAccess();
mutex_.Lock();
size_t size = SpaceUsedExcludingSelfNoLock();
mutex_.Unlock();
ConstAccess();
return size;
}
size_t MapFieldBase::SpaceUsedExcludingSelfNoLock() const {
if (repeated_field_ != nullptr) {
if (repeated_field_ != NULL) {
return repeated_field_->SpaceUsedExcludingSelfLong();
} else {
return 0;
@@ -125,177 +68,131 @@ size_t MapFieldBase::SpaceUsedExcludingSelfNoLock() const {
}
bool MapFieldBase::IsMapValid() const {
ConstAccess();
// "Acquire" insures the operation after SyncRepeatedFieldWithMap won't get
// executed before state_ is checked.
int state = state_.load(std::memory_order_acquire);
Atomic32 state = google::protobuf::internal::Acquire_Load(&state_);
return state != STATE_MODIFIED_REPEATED;
}
bool MapFieldBase::IsRepeatedFieldValid() const {
ConstAccess();
int state = state_.load(std::memory_order_acquire);
return state != STATE_MODIFIED_MAP;
}
void MapFieldBase::SetMapDirty() { state_ = STATE_MODIFIED_MAP; }
void MapFieldBase::SetMapDirty() {
MutableAccess();
// These are called by (non-const) mutator functions. So by our API it's the
// callers responsibility to have these calls properly ordered.
state_.store(STATE_MODIFIED_MAP, std::memory_order_relaxed);
}
void MapFieldBase::SetRepeatedDirty() { state_ = STATE_MODIFIED_REPEATED; }
void MapFieldBase::SetRepeatedDirty() {
MutableAccess();
// These are called by (non-const) mutator functions. So by our API it's the
// callers responsibility to have these calls properly ordered.
state_.store(STATE_MODIFIED_REPEATED, std::memory_order_relaxed);
}
void* MapFieldBase::MutableRepeatedPtrField() const { return repeated_field_; }
void MapFieldBase::SyncRepeatedFieldWithMap() const {
ConstAccess();
// acquire here matches with release below to ensure that we can only see a
// value of CLEAN after all previous changes have been synced.
switch (state_.load(std::memory_order_acquire)) {
case STATE_MODIFIED_MAP:
mutex_.Lock();
// Double check state, because another thread may have seen the same
// state and done the synchronization before the current thread.
if (state_.load(std::memory_order_relaxed) == STATE_MODIFIED_MAP) {
SyncRepeatedFieldWithMapNoLock();
state_.store(CLEAN, std::memory_order_release);
}
mutex_.Unlock();
ConstAccess();
break;
case CLEAN:
mutex_.Lock();
// Double check state
if (state_.load(std::memory_order_relaxed) == CLEAN) {
if (repeated_field_ == nullptr) {
repeated_field_ =
Arena::CreateMessage<RepeatedPtrField<Message> >(arena_);
}
state_.store(CLEAN, std::memory_order_release);
}
mutex_.Unlock();
ConstAccess();
break;
default:
break;
// "Acquire" insures the operation after SyncRepeatedFieldWithMap won't get
// executed before state_ is checked.
Atomic32 state = google::protobuf::internal::Acquire_Load(&state_);
if (state == STATE_MODIFIED_MAP) {
mutex_.Lock();
// Double check state, because another thread may have seen the same state
// and done the synchronization before the current thread.
if (state_ == STATE_MODIFIED_MAP) {
SyncRepeatedFieldWithMapNoLock();
// "Release" insures state_ can only be changed "after"
// SyncRepeatedFieldWithMapNoLock is finished.
google::protobuf::internal::Release_Store(&state_, CLEAN);
}
mutex_.Unlock();
}
}
void MapFieldBase::SyncRepeatedFieldWithMapNoLock() const {
if (repeated_field_ == nullptr) {
if (repeated_field_ == NULL) {
repeated_field_ = Arena::CreateMessage<RepeatedPtrField<Message> >(arena_);
}
}
void MapFieldBase::SyncMapWithRepeatedField() const {
ConstAccess();
// acquire here matches with release below to ensure that we can only see a
// value of CLEAN after all previous changes have been synced.
if (state_.load(std::memory_order_acquire) == STATE_MODIFIED_REPEATED) {
// "Acquire" insures the operation after SyncMapWithRepeatedField won't get
// executed before state_ is checked.
Atomic32 state = google::protobuf::internal::Acquire_Load(&state_);
if (state == STATE_MODIFIED_REPEATED) {
mutex_.Lock();
// Double check state, because another thread may have seen the same state
// and done the synchronization before the current thread.
if (state_.load(std::memory_order_relaxed) == STATE_MODIFIED_REPEATED) {
if (state_ == STATE_MODIFIED_REPEATED) {
SyncMapWithRepeatedFieldNoLock();
state_.store(CLEAN, std::memory_order_release);
// "Release" insures state_ can only be changed "after"
// SyncRepeatedFieldWithMapNoLock is finished.
google::protobuf::internal::Release_Store(&state_, CLEAN);
}
mutex_.Unlock();
ConstAccess();
}
}
// ------------------DynamicMapField------------------
DynamicMapField::DynamicMapField(const Message* default_entry)
: default_entry_(default_entry) {}
: default_entry_(default_entry) {
}
DynamicMapField::DynamicMapField(const Message* default_entry, Arena* arena)
DynamicMapField::DynamicMapField(const Message* default_entry,
Arena* arena)
: TypeDefinedMapFieldBase<MapKey, MapValueRef>(arena),
map_(arena),
default_entry_(default_entry) {}
default_entry_(default_entry) {
}
DynamicMapField::~DynamicMapField() {
if (arena_ != nullptr) return;
// DynamicMapField owns map values. Need to delete them before clearing the
// map.
for (auto& kv : map_) {
kv.second.DeleteData();
// DynamicMapField owns map values. Need to delete them before clearing
// the map.
for (Map<MapKey, MapValueRef>::iterator iter = map_.begin();
iter != map_.end(); ++iter) {
iter->second.DeleteData();
}
map_.clear();
}
int DynamicMapField::size() const { return GetMap().size(); }
void DynamicMapField::Clear() {
Map<MapKey, MapValueRef>* map = &const_cast<DynamicMapField*>(this)->map_;
if (MapFieldBase::arena_ == nullptr) {
for (Map<MapKey, MapValueRef>::iterator iter = map->begin();
iter != map->end(); ++iter) {
iter->second.DeleteData();
}
}
map->clear();
if (MapFieldBase::repeated_field_ != nullptr) {
MapFieldBase::repeated_field_->Clear();
}
// Data in map and repeated field are both empty, but we can't set status
// CLEAN which will invalidate previous reference to map.
MapFieldBase::SetMapDirty();
int DynamicMapField::size() const {
return GetMap().size();
}
bool DynamicMapField::ContainsMapKey(const MapKey& map_key) const {
bool DynamicMapField::ContainsMapKey(
const MapKey& map_key) const {
const Map<MapKey, MapValueRef>& map = GetMap();
Map<MapKey, MapValueRef>::const_iterator iter = map.find(map_key);
return iter != map.end();
}
void DynamicMapField::AllocateMapValue(MapValueRef* map_val) {
const FieldDescriptor* val_des = default_entry_->GetDescriptor()->map_value();
map_val->SetType(val_des->cpp_type());
// Allocate memory for the MapValueRef, and initialize to
// default value.
switch (val_des->cpp_type()) {
#define HANDLE_TYPE(CPPTYPE, TYPE) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: { \
TYPE* value = Arena::Create<TYPE>(MapFieldBase::arena_); \
map_val->SetValue(value); \
break; \
}
HANDLE_TYPE(INT32, int32_t);
HANDLE_TYPE(INT64, int64_t);
HANDLE_TYPE(UINT32, uint32_t);
HANDLE_TYPE(UINT64, uint64_t);
HANDLE_TYPE(DOUBLE, double);
HANDLE_TYPE(FLOAT, float);
HANDLE_TYPE(BOOL, bool);
HANDLE_TYPE(STRING, std::string);
HANDLE_TYPE(ENUM, int32_t);
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_MESSAGE: {
const Message& message =
default_entry_->GetReflection()->GetMessage(*default_entry_, val_des);
Message* value = message.New(MapFieldBase::arena_);
map_val->SetValue(value);
break;
}
}
}
bool DynamicMapField::InsertOrLookupMapValue(const MapKey& map_key,
MapValueRef* val) {
bool DynamicMapField::InsertOrLookupMapValue(
const MapKey& map_key, MapValueRef* val) {
// Always use mutable map because users may change the map value by
// MapValueRef.
Map<MapKey, MapValueRef>* map = MutableMap();
Map<MapKey, MapValueRef>::iterator iter = map->find(map_key);
if (iter == map->end()) {
MapValueRef& map_val = map_[map_key];
AllocateMapValue(&map_val);
// Insert
MapValueRef& map_val = (*map)[map_key];
const FieldDescriptor* val_des =
default_entry_->GetDescriptor()->FindFieldByName("value");
map_val.SetType(val_des->cpp_type());
// Allocate memory for the inserted MapValueRef, and initialize to
// default value.
switch (val_des->cpp_type()) {
#define HANDLE_TYPE(CPPTYPE, TYPE) \
case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: { \
TYPE * value = new TYPE(); \
map_val.SetValue(value); \
break; \
}
HANDLE_TYPE(INT32, int32);
HANDLE_TYPE(INT64, int64);
HANDLE_TYPE(UINT32, uint32);
HANDLE_TYPE(UINT64, uint64);
HANDLE_TYPE(DOUBLE, double);
HANDLE_TYPE(FLOAT, float);
HANDLE_TYPE(BOOL, bool);
HANDLE_TYPE(STRING, string);
HANDLE_TYPE(ENUM, int32);
#undef HANDLE_TYPE
case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
const Message& message = default_entry_->GetReflection()->GetMessage(
*default_entry_, val_des);
Message* value = message.New();
map_val.SetValue(value);
break;
}
}
val->CopyFrom(map_val);
return true;
}
@@ -305,19 +202,6 @@ bool DynamicMapField::InsertOrLookupMapValue(const MapKey& map_key,
return false;
}
bool DynamicMapField::LookupMapValue(const MapKey& map_key,
MapValueConstRef* val) const {
const Map<MapKey, MapValueRef>& map = GetMap();
Map<MapKey, MapValueRef>::const_iterator iter = map.find(map_key);
if (iter == map.end()) {
return false;
}
// map_key is already in the map. Make sure (*map)[map_key] is not called.
// [] may reorder the map and iterators.
val->CopyFrom(iter->second);
return true;
}
bool DynamicMapField::DeleteMapValue(const MapKey& map_key) {
MapFieldBase::SyncMapWithRepeatedField();
Map<MapKey, MapValueRef>::iterator iter = map_.find(map_key);
@@ -326,9 +210,7 @@ bool DynamicMapField::DeleteMapValue(const MapKey& map_key) {
}
// Set map dirty only if the delete is successful.
MapFieldBase::SetMapDirty();
if (MapFieldBase::arena_ == nullptr) {
iter->second.DeleteData();
}
iter->second.DeleteData();
map_.erase(iter);
return true;
}
@@ -353,155 +235,85 @@ void DynamicMapField::SetMapIteratorValue(MapIterator* map_iter) const {
map_iter->value_.CopyFrom(iter->second);
}
void DynamicMapField::MergeFrom(const MapFieldBase& other) {
GOOGLE_DCHECK(IsMapValid() && other.IsMapValid());
Map<MapKey, MapValueRef>* map = MutableMap();
const DynamicMapField& other_field =
reinterpret_cast<const DynamicMapField&>(other);
for (Map<MapKey, MapValueRef>::const_iterator other_it =
other_field.map_.begin();
other_it != other_field.map_.end(); ++other_it) {
Map<MapKey, MapValueRef>::iterator iter = map->find(other_it->first);
MapValueRef* map_val;
if (iter == map->end()) {
map_val = &map_[other_it->first];
AllocateMapValue(map_val);
} else {
map_val = &iter->second;
}
// Copy map value
const FieldDescriptor* field_descriptor =
default_entry_->GetDescriptor()->map_value();
switch (field_descriptor->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32: {
map_val->SetInt32Value(other_it->second.GetInt32Value());
break;
}
case FieldDescriptor::CPPTYPE_INT64: {
map_val->SetInt64Value(other_it->second.GetInt64Value());
break;
}
case FieldDescriptor::CPPTYPE_UINT32: {
map_val->SetUInt32Value(other_it->second.GetUInt32Value());
break;
}
case FieldDescriptor::CPPTYPE_UINT64: {
map_val->SetUInt64Value(other_it->second.GetUInt64Value());
break;
}
case FieldDescriptor::CPPTYPE_FLOAT: {
map_val->SetFloatValue(other_it->second.GetFloatValue());
break;
}
case FieldDescriptor::CPPTYPE_DOUBLE: {
map_val->SetDoubleValue(other_it->second.GetDoubleValue());
break;
}
case FieldDescriptor::CPPTYPE_BOOL: {
map_val->SetBoolValue(other_it->second.GetBoolValue());
break;
}
case FieldDescriptor::CPPTYPE_STRING: {
map_val->SetStringValue(other_it->second.GetStringValue());
break;
}
case FieldDescriptor::CPPTYPE_ENUM: {
map_val->SetEnumValue(other_it->second.GetEnumValue());
break;
}
case FieldDescriptor::CPPTYPE_MESSAGE: {
map_val->MutableMessageValue()->CopyFrom(
other_it->second.GetMessageValue());
break;
}
}
}
}
void DynamicMapField::Swap(MapFieldBase* other) {
DynamicMapField* other_field = down_cast<DynamicMapField*>(other);
std::swap(this->MapFieldBase::repeated_field_, other_field->repeated_field_);
map_.swap(other_field->map_);
// a relaxed swap of the atomic
auto other_state = other_field->state_.load(std::memory_order_relaxed);
auto this_state = this->MapFieldBase::state_.load(std::memory_order_relaxed);
other_field->state_.store(this_state, std::memory_order_relaxed);
this->MapFieldBase::state_.store(other_state, std::memory_order_relaxed);
}
void DynamicMapField::SyncRepeatedFieldWithMapNoLock() const {
const Reflection* reflection = default_entry_->GetReflection();
const FieldDescriptor* key_des = default_entry_->GetDescriptor()->map_key();
const FieldDescriptor* val_des = default_entry_->GetDescriptor()->map_value();
if (MapFieldBase::repeated_field_ == nullptr) {
MapFieldBase::repeated_field_ =
Arena::CreateMessage<RepeatedPtrField<Message> >(MapFieldBase::arena_);
const FieldDescriptor* key_des =
default_entry_->GetDescriptor()->FindFieldByName("key");
const FieldDescriptor* val_des =
default_entry_->GetDescriptor()->FindFieldByName("value");
if (MapFieldBase::repeated_field_ == NULL) {
if (MapFieldBase::arena_ == NULL) {
MapFieldBase::repeated_field_ = new RepeatedPtrField<Message>();
} else {
MapFieldBase::repeated_field_ =
Arena::CreateMessage<RepeatedPtrField<Message> >(
MapFieldBase::arena_);
}
}
MapFieldBase::repeated_field_->Clear();
for (Map<MapKey, MapValueRef>::const_iterator it = map_.begin();
it != map_.end(); ++it) {
Message* new_entry = default_entry_->New(MapFieldBase::arena_);
Message* new_entry = default_entry_->New();
MapFieldBase::repeated_field_->AddAllocated(new_entry);
const MapKey& map_key = it->first;
switch (key_des->cpp_type()) {
case FieldDescriptor::CPPTYPE_STRING:
case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
reflection->SetString(new_entry, key_des, map_key.GetStringValue());
break;
case FieldDescriptor::CPPTYPE_INT64:
case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
reflection->SetInt64(new_entry, key_des, map_key.GetInt64Value());
break;
case FieldDescriptor::CPPTYPE_INT32:
case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
reflection->SetInt32(new_entry, key_des, map_key.GetInt32Value());
break;
case FieldDescriptor::CPPTYPE_UINT64:
case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
reflection->SetUInt64(new_entry, key_des, map_key.GetUInt64Value());
break;
case FieldDescriptor::CPPTYPE_UINT32:
case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
reflection->SetUInt32(new_entry, key_des, map_key.GetUInt32Value());
break;
case FieldDescriptor::CPPTYPE_BOOL:
case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
reflection->SetBool(new_entry, key_des, map_key.GetBoolValue());
break;
case FieldDescriptor::CPPTYPE_DOUBLE:
case FieldDescriptor::CPPTYPE_FLOAT:
case FieldDescriptor::CPPTYPE_ENUM:
case FieldDescriptor::CPPTYPE_MESSAGE:
case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
GOOGLE_LOG(FATAL) << "Can't get here.";
break;
}
const MapValueRef& map_val = it->second;
switch (val_des->cpp_type()) {
case FieldDescriptor::CPPTYPE_STRING:
case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
reflection->SetString(new_entry, val_des, map_val.GetStringValue());
break;
case FieldDescriptor::CPPTYPE_INT64:
case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
reflection->SetInt64(new_entry, val_des, map_val.GetInt64Value());
break;
case FieldDescriptor::CPPTYPE_INT32:
case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
reflection->SetInt32(new_entry, val_des, map_val.GetInt32Value());
break;
case FieldDescriptor::CPPTYPE_UINT64:
case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
reflection->SetUInt64(new_entry, val_des, map_val.GetUInt64Value());
break;
case FieldDescriptor::CPPTYPE_UINT32:
case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
reflection->SetUInt32(new_entry, val_des, map_val.GetUInt32Value());
break;
case FieldDescriptor::CPPTYPE_BOOL:
case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
reflection->SetBool(new_entry, val_des, map_val.GetBoolValue());
break;
case FieldDescriptor::CPPTYPE_DOUBLE:
case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
reflection->SetDouble(new_entry, val_des, map_val.GetDoubleValue());
break;
case FieldDescriptor::CPPTYPE_FLOAT:
case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
reflection->SetFloat(new_entry, val_des, map_val.GetFloatValue());
break;
case FieldDescriptor::CPPTYPE_ENUM:
case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
reflection->SetEnumValue(new_entry, val_des, map_val.GetEnumValue());
break;
case FieldDescriptor::CPPTYPE_MESSAGE: {
case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
const Message& message = map_val.GetMessageValue();
reflection->MutableMessage(new_entry, val_des)->CopyFrom(message);
break;
@@ -513,80 +325,77 @@ void DynamicMapField::SyncRepeatedFieldWithMapNoLock() const {
void DynamicMapField::SyncMapWithRepeatedFieldNoLock() const {
Map<MapKey, MapValueRef>* map = &const_cast<DynamicMapField*>(this)->map_;
const Reflection* reflection = default_entry_->GetReflection();
const FieldDescriptor* key_des = default_entry_->GetDescriptor()->map_key();
const FieldDescriptor* val_des = default_entry_->GetDescriptor()->map_value();
const FieldDescriptor* key_des =
default_entry_->GetDescriptor()->FindFieldByName("key");
const FieldDescriptor* val_des =
default_entry_->GetDescriptor()->FindFieldByName("value");
// DynamicMapField owns map values. Need to delete them before clearing
// the map.
if (MapFieldBase::arena_ == nullptr) {
for (Map<MapKey, MapValueRef>::iterator iter = map->begin();
iter != map->end(); ++iter) {
iter->second.DeleteData();
}
for (Map<MapKey, MapValueRef>::iterator iter = map->begin();
iter != map->end(); ++iter) {
iter->second.DeleteData();
}
map->clear();
for (RepeatedPtrField<Message>::iterator it =
MapFieldBase::repeated_field_->begin();
it != MapFieldBase::repeated_field_->end(); ++it) {
// MapKey type will be set later.
MapKey map_key;
switch (key_des->cpp_type()) {
case FieldDescriptor::CPPTYPE_STRING:
case google::protobuf::FieldDescriptor::CPPTYPE_STRING:
map_key.SetStringValue(reflection->GetString(*it, key_des));
break;
case FieldDescriptor::CPPTYPE_INT64:
case google::protobuf::FieldDescriptor::CPPTYPE_INT64:
map_key.SetInt64Value(reflection->GetInt64(*it, key_des));
break;
case FieldDescriptor::CPPTYPE_INT32:
case google::protobuf::FieldDescriptor::CPPTYPE_INT32:
map_key.SetInt32Value(reflection->GetInt32(*it, key_des));
break;
case FieldDescriptor::CPPTYPE_UINT64:
case google::protobuf::FieldDescriptor::CPPTYPE_UINT64:
map_key.SetUInt64Value(reflection->GetUInt64(*it, key_des));
break;
case FieldDescriptor::CPPTYPE_UINT32:
case google::protobuf::FieldDescriptor::CPPTYPE_UINT32:
map_key.SetUInt32Value(reflection->GetUInt32(*it, key_des));
break;
case FieldDescriptor::CPPTYPE_BOOL:
case google::protobuf::FieldDescriptor::CPPTYPE_BOOL:
map_key.SetBoolValue(reflection->GetBool(*it, key_des));
break;
case FieldDescriptor::CPPTYPE_DOUBLE:
case FieldDescriptor::CPPTYPE_FLOAT:
case FieldDescriptor::CPPTYPE_ENUM:
case FieldDescriptor::CPPTYPE_MESSAGE:
case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE:
case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT:
case google::protobuf::FieldDescriptor::CPPTYPE_ENUM:
case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
GOOGLE_LOG(FATAL) << "Can't get here.";
break;
}
if (MapFieldBase::arena_ == nullptr) {
// Remove existing map value with same key.
Map<MapKey, MapValueRef>::iterator iter = map->find(map_key);
if (iter != map->end()) {
iter->second.DeleteData();
}
// Remove existing map value with same key.
Map<MapKey, MapValueRef>::iterator iter = map->find(map_key);
if (iter != map->end()) {
iter->second.DeleteData();
}
MapValueRef& map_val = (*map)[map_key];
map_val.SetType(val_des->cpp_type());
switch (val_des->cpp_type()) {
#define HANDLE_TYPE(CPPTYPE, TYPE, METHOD) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: { \
TYPE* value = Arena::Create<TYPE>(MapFieldBase::arena_); \
*value = reflection->Get##METHOD(*it, val_des); \
map_val.SetValue(value); \
break; \
}
HANDLE_TYPE(INT32, int32_t, Int32);
HANDLE_TYPE(INT64, int64_t, Int64);
HANDLE_TYPE(UINT32, uint32_t, UInt32);
HANDLE_TYPE(UINT64, uint64_t, UInt64);
#define HANDLE_TYPE(CPPTYPE, TYPE, METHOD) \
case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: { \
TYPE * value = new TYPE; \
*value = reflection->Get##METHOD(*it, val_des); \
map_val.SetValue(value); \
break; \
}
HANDLE_TYPE(INT32, int32, Int32);
HANDLE_TYPE(INT64, int64, Int64);
HANDLE_TYPE(UINT32, uint32, UInt32);
HANDLE_TYPE(UINT64, uint64, UInt64);
HANDLE_TYPE(DOUBLE, double, Double);
HANDLE_TYPE(FLOAT, float, Float);
HANDLE_TYPE(BOOL, bool, Bool);
HANDLE_TYPE(STRING, std::string, String);
HANDLE_TYPE(ENUM, int32_t, EnumValue);
HANDLE_TYPE(STRING, string, String);
HANDLE_TYPE(ENUM, int32, EnumValue);
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_MESSAGE: {
case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
const Message& message = reflection->GetMessage(*it, val_des);
Message* value = message.New(MapFieldBase::arena_);
Message* value = message.New();
value->CopyFrom(message);
map_val.SetValue(value);
break;
@@ -597,7 +406,7 @@ void DynamicMapField::SyncMapWithRepeatedFieldNoLock() const {
size_t DynamicMapField::SpaceUsedExcludingSelfNoLock() const {
size_t size = 0;
if (MapFieldBase::repeated_field_ != nullptr) {
if (MapFieldBase::repeated_field_ != NULL) {
size += MapFieldBase::repeated_field_->SpaceUsedExcludingSelfLong();
}
size += sizeof(map_);
@@ -607,27 +416,27 @@ size_t DynamicMapField::SpaceUsedExcludingSelfNoLock() const {
size += sizeof(it->first) * map_size;
size += sizeof(it->second) * map_size;
// If key is string, add the allocated space.
if (it->first.type() == FieldDescriptor::CPPTYPE_STRING) {
size += sizeof(std::string) * map_size;
if (it->first.type() == google::protobuf::FieldDescriptor::CPPTYPE_STRING) {
size += sizeof(string) * map_size;
}
// Add the allocated space in MapValueRef.
switch (it->second.type()) {
#define HANDLE_TYPE(CPPTYPE, TYPE) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: { \
size += sizeof(TYPE) * map_size; \
break; \
}
HANDLE_TYPE(INT32, int32_t);
HANDLE_TYPE(INT64, int64_t);
HANDLE_TYPE(UINT32, uint32_t);
HANDLE_TYPE(UINT64, uint64_t);
#define HANDLE_TYPE(CPPTYPE, TYPE) \
case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: { \
size += sizeof(TYPE) * map_size; \
break; \
}
HANDLE_TYPE(INT32, int32);
HANDLE_TYPE(INT64, int64);
HANDLE_TYPE(UINT32, uint32);
HANDLE_TYPE(UINT64, uint64);
HANDLE_TYPE(DOUBLE, double);
HANDLE_TYPE(FLOAT, float);
HANDLE_TYPE(BOOL, bool);
HANDLE_TYPE(STRING, std::string);
HANDLE_TYPE(ENUM, int32_t);
HANDLE_TYPE(STRING, string);
HANDLE_TYPE(ENUM, int32);
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_MESSAGE: {
case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
while (it != map_.end()) {
const Message& message = it->second.GetMessageValue();
size += message.GetReflection()->SpaceUsedLong(message);
@@ -643,5 +452,3 @@ size_t DynamicMapField::SpaceUsedExcludingSelfNoLock() const {
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
File diff suppressed because it is too large Load Diff
+100 -134
View File
@@ -32,72 +32,70 @@
#define GOOGLE_PROTOBUF_MAP_FIELD_INL_H__
#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/map.h>
#include <google/protobuf/map_field.h>
#include <google/protobuf/map_type_handler.h>
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
namespace google {
namespace protobuf {
namespace internal {
// UnwrapMapKey template
template <typename T>
template<typename T>
T UnwrapMapKey(const MapKey& map_key);
template <>
inline int32_t UnwrapMapKey<int32_t>(const MapKey& map_key) {
template<>
inline int32 UnwrapMapKey<int32>(const MapKey& map_key) {
return map_key.GetInt32Value();
}
template <>
inline uint32_t UnwrapMapKey<uint32_t>(const MapKey& map_key) {
template<>
inline uint32 UnwrapMapKey<uint32>(const MapKey& map_key) {
return map_key.GetUInt32Value();
}
template <>
inline int64_t UnwrapMapKey<int64_t>(const MapKey& map_key) {
template<>
inline int64 UnwrapMapKey<int64>(const MapKey& map_key) {
return map_key.GetInt64Value();
}
template <>
inline uint64_t UnwrapMapKey<uint64_t>(const MapKey& map_key) {
template<>
inline uint64 UnwrapMapKey<uint64>(const MapKey& map_key) {
return map_key.GetUInt64Value();
}
template <>
template<>
inline bool UnwrapMapKey<bool>(const MapKey& map_key) {
return map_key.GetBoolValue();
}
template <>
inline std::string UnwrapMapKey<std::string>(const MapKey& map_key) {
template<>
inline string UnwrapMapKey<string>(const MapKey& map_key) {
return map_key.GetStringValue();
}
// SetMapKey template
template <typename T>
template<typename T>
inline void SetMapKey(MapKey* map_key, const T& value);
template <>
inline void SetMapKey<int32_t>(MapKey* map_key, const int32_t& value) {
template<>
inline void SetMapKey<int32>(MapKey* map_key, const int32& value) {
map_key->SetInt32Value(value);
}
template <>
inline void SetMapKey<uint32_t>(MapKey* map_key, const uint32_t& value) {
template<>
inline void SetMapKey<uint32>(MapKey* map_key, const uint32& value) {
map_key->SetUInt32Value(value);
}
template <>
inline void SetMapKey<int64_t>(MapKey* map_key, const int64_t& value) {
template<>
inline void SetMapKey<int64>(MapKey* map_key, const int64& value) {
map_key->SetInt64Value(value);
}
template <>
inline void SetMapKey<uint64_t>(MapKey* map_key, const uint64_t& value) {
template<>
inline void SetMapKey<uint64>(MapKey* map_key, const uint64& value) {
map_key->SetUInt64Value(value);
}
template <>
template<>
inline void SetMapKey<bool>(MapKey* map_key, const bool& value) {
map_key->SetBoolValue(value);
}
template <>
inline void SetMapKey<std::string>(MapKey* map_key, const std::string& value) {
template<>
inline void SetMapKey<string>(MapKey* map_key, const string& value) {
map_key->SetStringValue(value);
}
@@ -106,7 +104,7 @@ template <typename Key, typename T>
typename Map<Key, T>::const_iterator&
TypeDefinedMapFieldBase<Key, T>::InternalGetIterator(
const MapIterator* map_iter) const {
return *reinterpret_cast<typename Map<Key, T>::const_iterator*>(
return *reinterpret_cast<typename Map<Key, T>::const_iterator *>(
map_iter->iter_);
}
@@ -122,14 +120,15 @@ void TypeDefinedMapFieldBase<Key, T>::MapEnd(MapIterator* map_iter) const {
}
template <typename Key, typename T>
bool TypeDefinedMapFieldBase<Key, T>::EqualIterator(
const MapIterator& a, const MapIterator& b) const {
bool TypeDefinedMapFieldBase<Key, T>::EqualIterator(const MapIterator& a,
const MapIterator& b)
const {
return InternalGetIterator(&a) == InternalGetIterator(&b);
}
template <typename Key, typename T>
void TypeDefinedMapFieldBase<Key, T>::IncreaseIterator(
MapIterator* map_iter) const {
void TypeDefinedMapFieldBase<Key, T>::IncreaseIterator(MapIterator* map_iter)
const {
++InternalGetIterator(map_iter);
SetMapIteratorValue(map_iter);
}
@@ -138,19 +137,20 @@ template <typename Key, typename T>
void TypeDefinedMapFieldBase<Key, T>::InitializeIterator(
MapIterator* map_iter) const {
map_iter->iter_ = new typename Map<Key, T>::const_iterator;
GOOGLE_CHECK(map_iter->iter_ != nullptr);
GOOGLE_CHECK(map_iter->iter_ != NULL);
}
template <typename Key, typename T>
void TypeDefinedMapFieldBase<Key, T>::DeleteIterator(
MapIterator* map_iter) const {
delete reinterpret_cast<typename Map<Key, T>::const_iterator*>(
void TypeDefinedMapFieldBase<Key, T>::DeleteIterator(MapIterator* map_iter)
const {
delete reinterpret_cast<typename Map<Key, T>::const_iterator *>(
map_iter->iter_);
}
template <typename Key, typename T>
void TypeDefinedMapFieldBase<Key, T>::CopyIterator(
MapIterator* this_iter, const MapIterator& that_iter) const {
MapIterator* this_iter,
const MapIterator& that_iter) const {
InternalGetIterator(this_iter) = InternalGetIterator(&that_iter);
this_iter->key_.SetType(that_iter.key_.type());
// MapValueRef::type() fails when containing data is null. However, if
@@ -164,35 +164,28 @@ void TypeDefinedMapFieldBase<Key, T>::CopyIterator(
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
int MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::size() const {
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
int MapField<Derived, Key, T, kKeyFieldType, kValueFieldType,
default_enum_value>::size() const {
MapFieldBase::SyncMapWithRepeatedField();
return static_cast<int>(impl_.GetMap().size());
}
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::Clear() {
if (this->MapFieldBase::repeated_field_ != nullptr) {
RepeatedPtrField<EntryType>* repeated_field =
reinterpret_cast<RepeatedPtrField<EntryType>*>(
this->MapFieldBase::repeated_field_);
repeated_field->Clear();
}
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType,
default_enum_value>::Clear() {
MapFieldBase::SyncMapWithRepeatedField();
impl_.MutableMap()->clear();
// Data in map and repeated field are both empty, but we can't set status
// CLEAN. Because clear is a generated API, we cannot invalidate previous
// reference to map.
MapFieldBase::SetMapDirty();
}
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
void MapField<Derived, Key, T, kKeyFieldType,
kValueFieldType>::SetMapIteratorValue(MapIterator* map_iter)
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType,
default_enum_value>::SetMapIteratorValue(MapIterator* map_iter)
const {
const Map<Key, T>& map = impl_.GetMap();
typename Map<Key, T>::const_iterator iter =
@@ -204,9 +197,9 @@ void MapField<Derived, Key, T, kKeyFieldType,
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
bool MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::ContainsMapKey(
const MapKey& map_key) const {
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
bool MapField<Derived, Key, T, kKeyFieldType, kValueFieldType,
default_enum_value>::ContainsMapKey(const MapKey& map_key) const {
const Map<Key, T>& map = impl_.GetMap();
const Key& key = UnwrapMapKey<Key>(map_key);
typename Map<Key, T>::const_iterator iter = map.find(key);
@@ -215,10 +208,10 @@ bool MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::ContainsMapKey(
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
bool MapField<Derived, Key, T, kKeyFieldType,
kValueFieldType>::InsertOrLookupMapValue(const MapKey& map_key,
MapValueRef* val) {
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
bool MapField<Derived, Key, T, kKeyFieldType, kValueFieldType,
default_enum_value>::InsertOrLookupMapValue(const MapKey& map_key,
MapValueRef* val) {
// Always use mutable map because users may change the map value by
// MapValueRef.
Map<Key, T>* map = MutableMap();
@@ -236,78 +229,47 @@ bool MapField<Derived, Key, T, kKeyFieldType,
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
bool MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::LookupMapValue(
const MapKey& map_key, MapValueConstRef* val) const {
const Map<Key, T>& map = GetMap();
const Key& key = UnwrapMapKey<Key>(map_key);
typename Map<Key, T>::const_iterator iter = map.find(key);
if (map.end() == iter) {
return false;
}
// Key is already in the map. Make sure (*map)[key] is not called.
// [] may reorder the map and iterators.
val->SetValue(&(iter->second));
return true;
}
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
bool MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::DeleteMapValue(
const MapKey& map_key) {
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
bool MapField<Derived, Key, T, kKeyFieldType, kValueFieldType,
default_enum_value>::DeleteMapValue(const MapKey& map_key) {
const Key& key = UnwrapMapKey<Key>(map_key);
return MutableMap()->erase(key);
}
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::MergeFrom(
const MapFieldBase& other) {
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType,
default_enum_value>::MergeFrom(const MapField& other) {
MapFieldBase::SyncMapWithRepeatedField();
const MapField& other_field = static_cast<const MapField&>(other);
other_field.SyncMapWithRepeatedField();
impl_.MergeFrom(other_field.impl_);
other.SyncMapWithRepeatedField();
impl_.MergeFrom(other.impl_);
MapFieldBase::SetMapDirty();
}
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::Swap(
MapFieldBase* other) {
MapFieldBase::Swap(other);
MapField* other_field = down_cast<MapField*>(other);
impl_.Swap(&other_field->impl_);
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType,
default_enum_value>::Swap(MapField* other) {
std::swap(this->MapFieldBase::repeated_field_, other->repeated_field_);
impl_.Swap(&other->impl_);
std::swap(this->MapFieldBase::state_, other->state_);
}
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
void MapField<Derived, Key, T, kKeyFieldType,
kValueFieldType>::UnsafeShallowSwap(MapFieldBase* other) {
InternalSwap(down_cast<MapField*>(other));
}
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType>::InternalSwap(
MapField* other) {
MapFieldBase::InternalSwap(other);
impl_.InternalSwap(&other->impl_);
}
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
void MapField<Derived, Key, T, kKeyFieldType,
kValueFieldType>::SyncRepeatedFieldWithMapNoLock() const {
if (this->MapFieldBase::repeated_field_ == nullptr) {
this->MapFieldBase::repeated_field_ =
Arena::CreateMessage<RepeatedPtrField<Message> >(
this->MapFieldBase::arena_);
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType,
default_enum_value>::SyncRepeatedFieldWithMapNoLock() const {
if (this->MapFieldBase::repeated_field_ == NULL) {
if (this->MapFieldBase::arena_ == NULL) {
this->MapFieldBase::repeated_field_ = new RepeatedPtrField<Message>();
} else {
this->MapFieldBase::repeated_field_ =
Arena::CreateMessage<RepeatedPtrField<Message> >(
this->MapFieldBase::arena_);
}
}
const Map<Key, T>& map = impl_.GetMap();
RepeatedPtrField<EntryType>* repeated_field =
@@ -322,8 +284,8 @@ void MapField<Derived, Key, T, kKeyFieldType,
// know that this MapEntry default_type has also already been constructed.
// So it's safe to just call internal_default_instance().
const Message* default_entry = Derived::internal_default_instance();
for (typename Map<Key, T>::const_iterator it = map.begin(); it != map.end();
++it) {
for (typename Map<Key, T>::const_iterator it = map.begin();
it != map.end(); ++it) {
EntryType* new_entry =
down_cast<EntryType*>(default_entry->New(this->MapFieldBase::arena_));
repeated_field->AddAllocated(new_entry);
@@ -334,18 +296,17 @@ void MapField<Derived, Key, T, kKeyFieldType,
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
void MapField<Derived, Key, T, kKeyFieldType,
kValueFieldType>::SyncMapWithRepeatedFieldNoLock() const {
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType,
default_enum_value>::SyncMapWithRepeatedFieldNoLock() const {
Map<Key, T>* map = const_cast<MapField*>(this)->impl_.MutableMap();
RepeatedPtrField<EntryType>* repeated_field =
reinterpret_cast<RepeatedPtrField<EntryType>*>(
this->MapFieldBase::repeated_field_);
GOOGLE_CHECK(this->MapFieldBase::repeated_field_ != nullptr);
GOOGLE_CHECK(this->MapFieldBase::repeated_field_ != NULL);
map->clear();
for (typename RepeatedPtrField<EntryType>::iterator it =
repeated_field->begin();
it != repeated_field->end(); ++it) {
repeated_field->begin(); it != repeated_field->end(); ++it) {
// Cast is needed because Map's api and internal storage is different when
// value is enum. For enum, we cannot cast an int to enum. Thus, we have to
// copy value. For other types, they have same exposed api type and internal
@@ -357,19 +318,24 @@ void MapField<Derived, Key, T, kKeyFieldType,
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
size_t MapField<Derived, Key, T, kKeyFieldType,
kValueFieldType>::SpaceUsedExcludingSelfNoLock() const {
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
size_t MapField<Derived, Key, T, kKeyFieldType, kValueFieldType,
default_enum_value>::SpaceUsedExcludingSelfNoLock() const {
size_t size = 0;
if (this->MapFieldBase::repeated_field_ != nullptr) {
if (this->MapFieldBase::repeated_field_ != NULL) {
size += this->MapFieldBase::repeated_field_->SpaceUsedExcludingSelfLong();
}
size += impl_.GetMap().SpaceUsedExcludingSelfLong();
Map<Key, T>* map = const_cast<MapField*>(this)->impl_.MutableMap();
size += sizeof(*map);
for (typename Map<Key, T>::iterator it = map->begin(); it != map->end();
++it) {
size += KeyTypeHandler::SpaceUsedInMapLong(it->first);
size += ValueTypeHandler::SpaceUsedInMapLong(it->second);
}
return size;
}
} // namespace internal
} // namespace protobuf
} // namespace google
} // namespace google
#endif // GOOGLE_PROTOBUF_MAP_FIELD_INL_H__
+33 -74
View File
@@ -31,30 +31,20 @@
#ifndef GOOGLE_PROTOBUF_MAP_FIELD_LITE_H__
#define GOOGLE_PROTOBUF_MAP_FIELD_LITE_H__
#include <type_traits>
#include <google/protobuf/parse_context.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/map.h>
#include <google/protobuf/map_entry_lite.h>
#include <google/protobuf/port.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/port_def.inc>
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
namespace google {
namespace protobuf {
namespace internal {
// This class provides access to map field using generated api. It is used for
// internal generated message implementation only. Users should never use this
// internal generated message implentation only. Users should never use this
// directly.
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType key_wire_type,
WireFormatLite::FieldType value_wire_type>
WireFormatLite::FieldType value_wire_type, int default_enum_value = 0>
class MapFieldLite {
// Define message type for internal repeated field.
typedef Derived EntryType;
@@ -63,9 +53,11 @@ class MapFieldLite {
typedef Map<Key, T> MapType;
typedef EntryType EntryTypeTrait;
constexpr MapFieldLite() {}
MapFieldLite() : arena_(NULL) { SetDefaultEnumValue(); }
explicit MapFieldLite(Arena* arena) : map_(arena) {}
explicit MapFieldLite(Arena* arena) : arena_(arena), map_(arena) {
SetDefaultEnumValue();
}
// Accessors
const Map<Key, T>& GetMap() const { return map_; }
@@ -81,79 +73,47 @@ class MapFieldLite {
}
}
void Swap(MapFieldLite* other) { map_.swap(other->map_); }
void InternalSwap(MapFieldLite* other) { map_.InternalSwap(other->map_); }
// Set default enum value only for proto2 map field whose value is enum type.
void SetDefaultEnumValue() {
MutableMap()->SetDefaultEnumValue(default_enum_value);
}
// Used in the implementation of parsing. Caller should take the ownership iff
// arena_ is nullptr.
// arena_ is NULL.
EntryType* NewEntry() const {
return Arena::CreateMessage<EntryType>(map_.arena());
if (arena_ == NULL) {
return new EntryType();
} else {
return Arena::CreateMessage<EntryType>(arena_);
}
}
// Used in the implementation of serializing enum value type. Caller should
// take the ownership iff arena_ is nullptr.
// take the ownership iff arena_ is NULL.
EntryType* NewEnumEntryWrapper(const Key& key, const T t) const {
return EntryType::EnumWrap(key, t, map_.arena_);
return EntryType::EnumWrap(key, t, arena_);
}
// Used in the implementation of serializing other value types. Caller should
// take the ownership iff arena_ is nullptr.
// take the ownership iff arena_ is NULL.
EntryType* NewEntryWrapper(const Key& key, const T& t) const {
return EntryType::Wrap(key, t, map_.arena_);
}
const char* _InternalParse(const char* ptr, ParseContext* ctx) {
typename Derived::template Parser<MapFieldLite, Map<Key, T>> parser(this);
return parser._InternalParse(ptr, ctx);
}
template <typename UnknownType>
const char* ParseWithEnumValidation(const char* ptr, ParseContext* ctx,
bool (*is_valid)(int), uint32_t field_num,
InternalMetadata* metadata) {
typename Derived::template Parser<MapFieldLite, Map<Key, T>> parser(this);
return parser.template ParseWithEnumValidation<UnknownType>(
ptr, ctx, is_valid, field_num, metadata);
return EntryType::Wrap(key, t, arena_);
}
private:
typedef void DestructorSkippable_;
Arena* arena_;
Map<Key, T> map_;
friend class ::PROTOBUF_NAMESPACE_ID::Arena;
friend class ::google::protobuf::Arena;
};
template <typename UnknownType, typename T>
struct EnumParseWrapper {
const char* _InternalParse(const char* ptr, ParseContext* ctx) {
return map_field->template ParseWithEnumValidation<UnknownType>(
ptr, ctx, is_valid, field_num, metadata);
}
T* map_field;
bool (*is_valid)(int);
uint32_t field_num;
InternalMetadata* metadata;
};
// Helper function because the typenames of maps are horrendous to print. This
// leverages compiler type deduction, to keep all type data out of the
// generated code
template <typename UnknownType, typename T>
EnumParseWrapper<UnknownType, T> InitEnumParseWrapper(
T* map_field, bool (*is_valid)(int), uint32_t field_num,
InternalMetadata* metadata) {
return EnumParseWrapper<UnknownType, T>{map_field, is_valid, field_num,
metadata};
}
// True if IsInitialized() is true for value field in all elements of t. T is
// expected to be message. It's useful to have this helper here to keep the
// protobuf compiler from ever having to emit loops in IsInitialized() methods.
// We want the C++ compiler to inline this or not as it sees fit.
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType key_wire_type,
WireFormatLite::FieldType value_wire_type>
bool AllAreInitialized(const MapFieldLite<Derived, Key, T, key_wire_type,
value_wire_type>& field) {
const auto& t = field.GetMap();
template <typename Key, typename T>
bool AllAreInitialized(const Map<Key, T>& t) {
for (typename Map<Key, T>::const_iterator it = t.begin(); it != t.end();
++it) {
if (!it->second.IsInitialized()) return false;
@@ -166,19 +126,18 @@ struct MapEntryToMapField : MapEntryToMapField<typename MEntry::SuperType> {};
template <typename T, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
struct MapEntryToMapField<
MapEntryLite<T, Key, Value, kKeyFieldType, kValueFieldType>> {
typedef MapFieldLite<
MapEntryLite<T, Key, Value, kKeyFieldType, kValueFieldType>, Key, Value,
kKeyFieldType, kValueFieldType>
WireFormatLite::FieldType kValueFieldType, int default_enum_value>
struct MapEntryToMapField<MapEntryLite<T, Key, Value, kKeyFieldType,
kValueFieldType, default_enum_value> > {
typedef MapFieldLite<MapEntryLite<T, Key, Value, kKeyFieldType,
kValueFieldType, default_enum_value>,
Key, Value, kKeyFieldType, kValueFieldType,
default_enum_value>
MapFieldType;
};
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_MAP_FIELD_LITE_H__

Some files were not shown because too many files have changed in this diff Show More