commit
32bea52ee6
319 changed files with 45881 additions and 46930 deletions
@ -0,0 +1,135 @@ |
|||||||
|
# How to use `protobuf_generate` |
||||||
|
|
||||||
|
This document explains how to use the function `protobuf_generate` which is provided by protobuf's CMake module. |
||||||
|
|
||||||
|
## Usage |
||||||
|
|
||||||
|
In the same directory that called `find_package(protobuf CONFIG)` and any of its subdirectories, the CMake function `protobuf_generate` is made available by |
||||||
|
[`protobuf-generate.cmake`](../cmake/protobuf-generate.cmake). It can be used to automatically generate source files from `.proto` schema files at build time. |
||||||
|
|
||||||
|
### Basic example |
||||||
|
|
||||||
|
Let us see how `protobuf_generate` can be used to generate and compile the source files of a proto schema whenever an object target called `proto-objects` is built. |
||||||
|
|
||||||
|
Given the following directory structure: |
||||||
|
|
||||||
|
- `proto/helloworld/helloworld.proto` |
||||||
|
- `CMakeLists.txt` |
||||||
|
|
||||||
|
where `helloworld.proto` is a protobuf schema file and `CMakeLists.txt` contains: |
||||||
|
|
||||||
|
```cmake |
||||||
|
find_package(protobuf CONFIG REQUIRED) |
||||||
|
|
||||||
|
add_library(proto-objects OBJECT "${CMAKE_CURRENT_LIST_DIR}/proto/helloworld/helloworld.proto") |
||||||
|
|
||||||
|
target_link_libraries(proto-objects PUBLIC protobuf::libprotobuf) |
||||||
|
|
||||||
|
set(PROTO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") |
||||||
|
|
||||||
|
target_include_directories(proto-objects PUBLIC "$<BUILD_INTERFACE:${PROTO_BINARY_DIR}>") |
||||||
|
|
||||||
|
protobuf_generate( |
||||||
|
TARGET proto-objects |
||||||
|
IMPORT_DIRS "${CMAKE_CURRENT_LIST_DIR}/proto" |
||||||
|
PROTOC_OUT_DIR "${PROTO_BINARY_DIR}") |
||||||
|
``` |
||||||
|
|
||||||
|
Building the target `proto-objects` will generate the files: |
||||||
|
|
||||||
|
- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.pb.h` |
||||||
|
- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.pb.cc` |
||||||
|
|
||||||
|
and (depending on the build system) output: |
||||||
|
|
||||||
|
```shell |
||||||
|
[build] [1/2] Running cpp protocol buffer compiler on /proto/helloworld/helloworld.proto |
||||||
|
[build] [2/2] Building CXX object /build/generated/helloworld/helloworld.pb.cc.o |
||||||
|
``` |
||||||
|
|
||||||
|
### gRPC example |
||||||
|
|
||||||
|
`protobuf_generate` can also be customized to invoke plugins like gRPC's `grpc_cpp_plugin`. Given the same directory structure as in the [basic example](#basic-example) |
||||||
|
and let `CMakeLists.txt` contain: |
||||||
|
|
||||||
|
```cmake |
||||||
|
find_package(gRPC CONFIG REQUIRED) |
||||||
|
|
||||||
|
add_library(proto-objects OBJECT "${CMAKE_CURRENT_LIST_DIR}/proto/helloworld/helloworld.proto") |
||||||
|
|
||||||
|
target_link_libraries(proto-objects PUBLIC protobuf::libprotobuf gRPC::grpc++) |
||||||
|
|
||||||
|
set(PROTO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") |
||||||
|
set(PROTO_IMPORT_DIRS "${CMAKE_CURRENT_LIST_DIR}/proto") |
||||||
|
|
||||||
|
target_include_directories(proto-objects PUBLIC "$<BUILD_INTERFACE:${PROTO_BINARY_DIR}>") |
||||||
|
|
||||||
|
protobuf_generate( |
||||||
|
TARGET proto-objects |
||||||
|
IMPORT_DIRS ${PROTO_IMPORT_DIRS} |
||||||
|
PROTOC_OUT_DIR "${PROTO_BINARY_DIR}") |
||||||
|
|
||||||
|
protobuf_generate( |
||||||
|
TARGET proto-objects |
||||||
|
LANGUAGE grpc |
||||||
|
GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc |
||||||
|
PLUGIN "protoc-gen-grpc=\$<TARGET_FILE:gRPC::grpc_cpp_plugin>" |
||||||
|
IMPORT_DIRS ${PROTO_IMPORT_DIRS} |
||||||
|
PROTOC_OUT_DIR "${PROTO_BINARY_DIR}") |
||||||
|
``` |
||||||
|
|
||||||
|
Then building `proto-objects` will generate and compile: |
||||||
|
|
||||||
|
- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.pb.h` |
||||||
|
- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.pb.cc` |
||||||
|
- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.grpc.pb.h` |
||||||
|
- `${CMAKE_CURRENT_BINARY_DIR}/generated/helloworld/helloworld.grpc.pb.cc` |
||||||
|
|
||||||
|
And `protoc` will automatically be re-run whenever the schema files change and `proto-objects` is built. |
||||||
|
|
||||||
|
### Note on unity builds |
||||||
|
|
||||||
|
Since protobuf's generated source files are unsuited for [jumbo/unity builds](https://cmake.org/cmake/help/latest/prop_tgt/UNITY_BUILD.html) it is recommended |
||||||
|
to exclude them from such builds which can be achieved by adjusting their properties: |
||||||
|
|
||||||
|
```cmake |
||||||
|
protobuf_generate( |
||||||
|
OUT_VAR PROTO_GENERATED_FILES |
||||||
|
...) |
||||||
|
|
||||||
|
set_source_files_properties(${PROTO_GENERATED_FILES} PROPERTIES SKIP_UNITY_BUILD_INCLUSION on) |
||||||
|
``` |
||||||
|
|
||||||
|
## How it works |
||||||
|
|
||||||
|
For each source file ending in `proto` of the argument provided to `TARGET` or each file provided through `PROTOS`, `protobuf_generate` will set up |
||||||
|
a [add_custom_command](https://cmake.org/cmake/help/latest/command/add_custom_command.html) which depends on `protobuf::protoc` and the proto files. |
||||||
|
It declares the generated source files as `OUTPUT` which means that any target that depends on them will automatically cause the custom command to execute |
||||||
|
when it is brought up to date. The command itself is made up of the arguments for `protoc`, like the output directory, the schema files, the language to |
||||||
|
generate for, the plugins to use, etc. |
||||||
|
|
||||||
|
## Reference |
||||||
|
|
||||||
|
Arguments accepted by `protobuf_generate`. |
||||||
|
|
||||||
|
Flag arguments: |
||||||
|
|
||||||
|
- `APPEND_PATH` — A flag that causes the base path of all proto schema files to be added to `IMPORT_DIRS`. |
||||||
|
|
||||||
|
Single-value arguments: |
||||||
|
|
||||||
|
- `LANGUAGE` — A single value: cpp or python. Determines what kind of source files are being generated. |
||||||
|
- `OUT_VAR` — Name of a CMake variable that will be filled with the paths to the generated source files. |
||||||
|
- `EXPORT_MACRO` — Name of a macro that is applied to all generated Protobuf message classes and extern variables. It can, for example, be used to declare DLL exports. |
||||||
|
- `PROTOC_OUT_DIR` — Output directory of generated source files. Defaults to `CMAKE_CURRENT_BINARY_DIR`. |
||||||
|
- `PLUGIN` — An optional plugin executable. This could, for example, be the path to `grpc_cpp_plugin`. |
||||||
|
- `PLUGIN_OPTIONS` — Additional options provided to the plugin, such as `generate_mock_code=true` for the gRPC cpp plugin. |
||||||
|
- `DEPENDENCIES` — Arguments forwarded to the `DEPENDS` of the underlying `add_custom_command` invocation. |
||||||
|
- `TARGET` — CMake target that will have the generated files added as sources. |
||||||
|
|
||||||
|
Multi-value arguments: |
||||||
|
|
||||||
|
- `PROTOS` — List of proto schema files. If omitted, then every source file ending in *proto* of `TARGET` will be used. |
||||||
|
- `IMPORT_DIRS` — A common parent directory for the schema files. For example, if the schema file is `proto/helloworld/helloworld.proto` and the import directory `proto/` then the generated files are `${PROTOC_OUT_DIR}/helloworld/helloworld.pb.h` and `${PROTOC_OUT_DIR}/helloworld/helloworld.pb.cc`. |
||||||
|
- `GENERATE_EXTENSIONS` — If LANGUAGE is omitted then this must be set to the extensions that protoc generates. |
||||||
|
- `PROTOC_OPTIONS` — Additional arguments that are forwarded to protoc. |
@ -0,0 +1,42 @@ |
|||||||
|
# Publish pre-compiled protoc artifacts |
||||||
|
``protoc`` is the compiler for ``.proto`` files. It generates language bindings |
||||||
|
for the messages and/or RPC services from ``.proto`` files. |
||||||
|
|
||||||
|
Because ``protoc`` is a native executable, the scripts under this directory |
||||||
|
publish a ``protoc`` executable (a.k.a. artifact) to Maven repositories. The |
||||||
|
artifact can be used by build automation tools so that users would not need to |
||||||
|
compile and install ``protoc`` for their systems. |
||||||
|
|
||||||
|
If you would like us to publish protoc artifact for a new platform, please |
||||||
|
open an issue to request it. |
||||||
|
|
||||||
|
## Maven Location |
||||||
|
The published protoc artifacts are available on Maven here: |
||||||
|
|
||||||
|
https://repo.maven.apache.org/maven2/com/google/protobuf/protoc/ |
||||||
|
|
||||||
|
## Versioning |
||||||
|
The version of the ``protoc`` artifact must be the same as the version of the |
||||||
|
Protobuf project. |
||||||
|
|
||||||
|
## Artifact name |
||||||
|
The name of a published ``protoc`` artifact is in the following format: |
||||||
|
``protoc-<version>-<os>-<arch>.exe``, e.g., ``protoc-3.6.1-linux-x86_64.exe``. |
||||||
|
|
||||||
|
Note that artifacts for linux/macos also have the `.exe` suffix but they are |
||||||
|
not windows binaries. |
||||||
|
|
||||||
|
## System requirement |
||||||
|
Install [Apache Maven](http://maven.apache.org/) if you don't have it. |
||||||
|
|
||||||
|
The scripts only work under Unix-like environments, e.g., Linux, MacOSX, and |
||||||
|
Cygwin or MinGW for Windows. Please see ``README.md`` of the Protobuf project |
||||||
|
for how to set up the build environment. |
||||||
|
|
||||||
|
## Tested build environments |
||||||
|
We have successfully built artifacts on the following environments: |
||||||
|
- Linux x86_32 and x86_64: |
||||||
|
- Centos 6.9 (within Docker 1.6.1) |
||||||
|
- Ubuntu 14.04.5 64-bit |
||||||
|
- Linux aarch_64: Cross compiled with `g++-aarch64-linux-gnu` on Ubuntu 14.04.5 64-bit |
||||||
|
- Mac OS X x86_32 and x86_64: Mac OS X 10.9.5 |
@ -0,0 +1,18 @@ |
|||||||
|
# We run our staleness tests as release-type jobs only. They are not really |
||||||
|
# part of the release process, but the release job type allows us to run the |
||||||
|
# tests on a schedule only (not presubmit or postsubmit). |
||||||
|
|
||||||
|
# Location of the build script in repository |
||||||
|
build_file: "protobuf/kokoro/linux/bazel.sh" |
||||||
|
timeout_mins: 15 |
||||||
|
|
||||||
|
env_vars { |
||||||
|
key: "BAZEL_TARGETS" |
||||||
|
value: "//src:cmake_lists_staleness_test" |
||||||
|
} |
||||||
|
|
||||||
|
action { |
||||||
|
define_artifacts { |
||||||
|
regex: "**/sponge_log.*" |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,3 @@ |
|||||||
PROTOC_VERSION = '21.6' |
PROTOC_VERSION = "21.7" |
||||||
PROTOBUF_JAVA_VERSION = '3.21.6' |
PROTOBUF_JAVA_VERSION = "3.21.7" |
||||||
PROTOBUF_PYTHON_VERSION = '4.21.6' |
PROTOBUF_PYTHON_VERSION = "4.21.7" |
||||||
|
@ -0,0 +1,215 @@ |
|||||||
|
# Protocol Buffers - Google's data interchange format |
||||||
|
# Copyright 2008 Google Inc. All rights reserved. |
||||||
|
# https://developers.google.com/protocol-buffers/ |
||||||
|
# |
||||||
|
# Redistribution and use in source and binary forms, with or without |
||||||
|
# modification, are permitted provided that the following conditions are |
||||||
|
# met: |
||||||
|
# |
||||||
|
# * Redistributions of source code must retain the above copyright |
||||||
|
# notice, this list of conditions and the following disclaimer. |
||||||
|
# * Redistributions in binary form must reproduce the above |
||||||
|
# copyright notice, this list of conditions and the following disclaimer |
||||||
|
# in the documentation and/or other materials provided with the |
||||||
|
# distribution. |
||||||
|
# * Neither the name of Google Inc. nor the names of its |
||||||
|
# contributors may be used to endorse or promote products derived from |
||||||
|
# this software without specific prior written permission. |
||||||
|
# |
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||||
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
|
||||||
|
"""Test use of numpy types with repeated and non-repeated scalar fields.""" |
||||||
|
|
||||||
|
import unittest |
||||||
|
|
||||||
|
import numpy as np |
||||||
|
|
||||||
|
from google.protobuf import unittest_pb2 |
||||||
|
from google.protobuf.internal import testing_refleaks |
||||||
|
|
||||||
|
message = unittest_pb2.TestAllTypes() |
||||||
|
np_float_scalar = np.float64(0.0) |
||||||
|
np_1_float_array = np.zeros(shape=(1,), dtype=np.float64) |
||||||
|
np_2_float_array = np.zeros(shape=(2,), dtype=np.float64) |
||||||
|
np_11_float_array = np.zeros(shape=(1, 1), dtype=np.float64) |
||||||
|
np_22_float_array = np.zeros(shape=(2, 2), dtype=np.float64) |
||||||
|
|
||||||
|
np_int_scalar = np.int64(0) |
||||||
|
np_1_int_array = np.zeros(shape=(1,), dtype=np.int64) |
||||||
|
np_2_int_array = np.zeros(shape=(2,), dtype=np.int64) |
||||||
|
np_11_int_array = np.zeros(shape=(1, 1), dtype=np.int64) |
||||||
|
np_22_int_array = np.zeros(shape=(2, 2), dtype=np.int64) |
||||||
|
|
||||||
|
np_uint_scalar = np.uint64(0) |
||||||
|
np_1_uint_array = np.zeros(shape=(1,), dtype=np.uint64) |
||||||
|
np_2_uint_array = np.zeros(shape=(2,), dtype=np.uint64) |
||||||
|
np_11_uint_array = np.zeros(shape=(1, 1), dtype=np.uint64) |
||||||
|
np_22_uint_array = np.zeros(shape=(2, 2), dtype=np.uint64) |
||||||
|
|
||||||
|
np_bool_scalar = np.bool_(False) |
||||||
|
np_1_bool_array = np.zeros(shape=(1,), dtype=np.bool_) |
||||||
|
np_2_bool_array = np.zeros(shape=(2,), dtype=np.bool_) |
||||||
|
np_11_bool_array = np.zeros(shape=(1, 1), dtype=np.bool_) |
||||||
|
np_22_bool_array = np.zeros(shape=(2, 2), dtype=np.bool_) |
||||||
|
|
||||||
|
|
||||||
|
@testing_refleaks.TestCase |
||||||
|
class NumpyIntProtoTest(unittest.TestCase): |
||||||
|
|
||||||
|
# Assigning dim 1 ndarray of ints to repeated field should pass |
||||||
|
def testNumpyDim1IntArrayToRepeated_IsValid(self): |
||||||
|
message.repeated_int64[:] = np_1_int_array |
||||||
|
message.repeated_int64[:] = np_2_int_array |
||||||
|
|
||||||
|
message.repeated_uint64[:] = np_1_uint_array |
||||||
|
message.repeated_uint64[:] = np_2_uint_array |
||||||
|
|
||||||
|
# Assigning dim 2 ndarray of ints to repeated field should fail |
||||||
|
def testNumpyDim2IntArrayToRepeated_RaisesTypeError(self): |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.repeated_int64[:] = np_11_int_array |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.repeated_int64[:] = np_22_int_array |
||||||
|
|
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.repeated_uint64[:] = np_11_uint_array |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.repeated_uint64[:] = np_22_uint_array |
||||||
|
|
||||||
|
# Assigning any ndarray of floats to repeated int field should fail |
||||||
|
def testNumpyFloatArrayToRepeated_RaisesTypeError(self): |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.repeated_int64[:] = np_1_float_array |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.repeated_int64[:] = np_11_float_array |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.repeated_int64[:] = np_22_float_array |
||||||
|
|
||||||
|
# Assigning any np int to scalar field should pass |
||||||
|
def testNumpyIntScalarToScalar_IsValid(self): |
||||||
|
message.optional_int64 = np_int_scalar |
||||||
|
message.optional_uint64 = np_uint_scalar |
||||||
|
|
||||||
|
# Assigning any ndarray of ints to scalar field should fail |
||||||
|
def testNumpyIntArrayToScalar_RaisesTypeError(self): |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.optional_int64 = np_1_int_array |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.optional_int64 = np_11_int_array |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.optional_int64 = np_22_int_array |
||||||
|
|
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.optional_uint64 = np_1_uint_array |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.optional_uint64 = np_11_uint_array |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.optional_uint64 = np_22_uint_array |
||||||
|
|
||||||
|
# Assigning any ndarray of floats to scalar field should fail |
||||||
|
def testNumpyFloatArrayToScalar_RaisesTypeError(self): |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.optional_int64 = np_1_float_array |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.optional_int64 = np_11_float_array |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.optional_int64 = np_22_float_array |
||||||
|
|
||||||
|
|
||||||
|
@testing_refleaks.TestCase |
||||||
|
class NumpyFloatProtoTest(unittest.TestCase): |
||||||
|
|
||||||
|
# Assigning dim 1 ndarray of floats to repeated field should pass |
||||||
|
def testNumpyDim1FloatArrayToRepeated_IsValid(self): |
||||||
|
message.repeated_float[:] = np_1_float_array |
||||||
|
message.repeated_float[:] = np_2_float_array |
||||||
|
|
||||||
|
# Assigning dim 2 ndarray of floats to repeated field should fail |
||||||
|
def testNumpyDim2FloatArrayToRepeated_RaisesTypeError(self): |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.repeated_float[:] = np_11_float_array |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.repeated_float[:] = np_22_float_array |
||||||
|
|
||||||
|
# Assigning any np float to scalar field should pass |
||||||
|
def testNumpyFloatScalarToScalar_IsValid(self): |
||||||
|
message.optional_float = np_float_scalar |
||||||
|
|
||||||
|
# Assigning any ndarray of float to scalar field should fail |
||||||
|
def testNumpyFloatArrayToScalar_RaisesTypeError(self): |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.optional_float = np_1_float_array |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.optional_float = np_11_float_array |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.optional_float = np_22_float_array |
||||||
|
|
||||||
|
|
||||||
|
@testing_refleaks.TestCase |
||||||
|
class NumpyBoolProtoTest(unittest.TestCase): |
||||||
|
|
||||||
|
# Assigning dim 1 ndarray of bool to repeated field should pass |
||||||
|
def testNumpyDim1BoolArrayToRepeated_IsValid(self): |
||||||
|
message.repeated_bool[:] = np_1_bool_array |
||||||
|
message.repeated_bool[:] = np_2_bool_array |
||||||
|
|
||||||
|
# Assigning dim 2 ndarray of bool to repeated field should fail |
||||||
|
def testNumpyDim2BoolArrayToRepeated_RaisesTypeError(self): |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.repeated_bool[:] = np_11_bool_array |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.repeated_bool[:] = np_22_bool_array |
||||||
|
|
||||||
|
# Assigning any np bool to scalar field should pass |
||||||
|
def testNumpyBoolScalarToScalar_IsValid(self): |
||||||
|
message.optional_bool = np_bool_scalar |
||||||
|
|
||||||
|
# Assigning any ndarray of bool to scalar field should fail |
||||||
|
def testNumpyBoolArrayToScalar_RaisesTypeError(self): |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.optional_bool = np_1_bool_array |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.optional_bool = np_11_bool_array |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
message.optional_bool = np_22_bool_array |
||||||
|
|
||||||
|
|
||||||
|
@testing_refleaks.TestCase |
||||||
|
class NumpyProtoIndexingTest(unittest.TestCase): |
||||||
|
|
||||||
|
def testNumpyIntScalarIndexing_Passes(self): |
||||||
|
data = unittest_pb2.TestAllTypes(repeated_int64=[0, 1, 2]) |
||||||
|
self.assertEqual(0, data.repeated_int64[np.int64(0)]) |
||||||
|
|
||||||
|
def testNumpyNegative1IntScalarIndexing_Passes(self): |
||||||
|
data = unittest_pb2.TestAllTypes(repeated_int64=[0, 1, 2]) |
||||||
|
self.assertEqual(2, data.repeated_int64[np.int64(-1)]) |
||||||
|
|
||||||
|
def testNumpyFloatScalarIndexing_Fails(self): |
||||||
|
data = unittest_pb2.TestAllTypes(repeated_int64=[0, 1, 2]) |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
_ = data.repeated_int64[np.float64(0.0)] |
||||||
|
|
||||||
|
def testNumpyIntArrayIndexing_Fails(self): |
||||||
|
data = unittest_pb2.TestAllTypes(repeated_int64=[0, 1, 2]) |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
_ = data.repeated_int64[np.array([0])] |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
_ = data.repeated_int64[np.ndarray((1,), buffer=np.array([0]), dtype=int)] |
||||||
|
with self.assertRaises(TypeError): |
||||||
|
_ = data.repeated_int64[np.ndarray((1, 1), |
||||||
|
buffer=np.array([0]), |
||||||
|
dtype=int)] |
||||||
|
|
||||||
|
if __name__ == '__main__': |
||||||
|
unittest.main() |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,155 @@ |
|||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
// This file provides alignment utilities for use in arenas.
|
||||||
|
//
|
||||||
|
// `ArenaAlign` constains a single `align` data member and provides
|
||||||
|
// the below functions which operate on the given alignment.
|
||||||
|
//
|
||||||
|
// Ceil(size_t n) - rounds `n` up to the nearest `align` boundary.
|
||||||
|
// Floor(size_t n) - rounds `n` down to the nearest `align` boundary.
|
||||||
|
// Ceil(T* P) - rounds `p` up to the nearest `align` boundary.
|
||||||
|
// IsAligned(size_t n) - returns true if `n` is aligned to `align`
|
||||||
|
// IsAligned(T* p) - returns true if `p` is aligned to `align`
|
||||||
|
// CheckAligned(T* p) - returns `p`. Checks alignment of `p` in debug.
|
||||||
|
//
|
||||||
|
// Additionally there is an optimized `CeilDefaultAligned(T*)` method which is
|
||||||
|
// equivalent to `Ceil(ArenaAlignDefault().CheckAlign(p))` but more efficiently
|
||||||
|
// implemented as a 'check only' for ArenaAlignDefault.
|
||||||
|
//
|
||||||
|
// These classes allow for generic arena logic using 'alignment policies'.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
//
|
||||||
|
// template <Align>
|
||||||
|
// void* NaiveAlloc(size_t n, Align align) {
|
||||||
|
// align.CheckAligned(n);
|
||||||
|
// uint8_t* ptr = align.CeilDefaultAligned(ptr_);
|
||||||
|
// ptr_ += n;
|
||||||
|
// return ptr;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// void CallSites() {
|
||||||
|
// void *p1 = NaiveAlloc(n, ArenaAlignDefault());
|
||||||
|
// void *p2 = NaiveAlloc(n, ArenaAlignAs(32));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
#ifndef GOOGLE_PROTOBUF_ARENA_ALIGN_H__ |
||||||
|
#define GOOGLE_PROTOBUF_ARENA_ALIGN_H__ |
||||||
|
|
||||||
|
#include <cstddef> |
||||||
|
#include <cstdint> |
||||||
|
|
||||||
|
#include "google/protobuf/stubs/logging.h" |
||||||
|
#include "google/protobuf/stubs/common.h" |
||||||
|
#include "absl/numeric/bits.h" |
||||||
|
|
||||||
|
namespace google { |
||||||
|
namespace protobuf { |
||||||
|
namespace internal { |
||||||
|
|
||||||
|
struct ArenaAlignDefault { |
||||||
|
static constexpr size_t align = 8; // NOLINT
|
||||||
|
|
||||||
|
static constexpr bool IsAligned(size_t n) { return (n & (align - 1)) == 0; } |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
static bool IsAligned(T* ptr) { |
||||||
|
return (reinterpret_cast<uintptr_t>(ptr) & (align - 1)) == 0; |
||||||
|
} |
||||||
|
|
||||||
|
static constexpr size_t Ceil(size_t n) { return (n + align - 1) & -align; } |
||||||
|
static constexpr size_t Floor(size_t n) { return (n & ~(align - 1)); } |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
T* Ceil(T* ptr) const { |
||||||
|
uintptr_t intptr = reinterpret_cast<uintptr_t>(ptr); |
||||||
|
return reinterpret_cast<T*>((intptr + align - 1) & -align); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
T* CeilDefaultAligned(T* ptr) const { |
||||||
|
return ArenaAlignDefault().CheckAligned(ptr); |
||||||
|
} |
||||||
|
|
||||||
|
// Address sanitizer enabled alignment check
|
||||||
|
template <typename T> |
||||||
|
static T* CheckAligned(T* ptr) { |
||||||
|
GOOGLE_DCHECK(IsAligned(ptr)) << static_cast<void*>(ptr); |
||||||
|
return ptr; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
struct ArenaAlign { |
||||||
|
static constexpr bool IsDefault() { return false; }; |
||||||
|
|
||||||
|
size_t align = 8; |
||||||
|
|
||||||
|
constexpr bool IsAligned(size_t n) const { return (n & (align - 1)) == 0; } |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
bool IsAligned(T* ptr) const { |
||||||
|
return (reinterpret_cast<uintptr_t>(ptr) & (align - 1)) == 0; |
||||||
|
} |
||||||
|
|
||||||
|
constexpr size_t Ceil(size_t n) const { return (n + align - 1) & -align; } |
||||||
|
constexpr size_t Floor(size_t n) const { return (n & ~(align - 1)); } |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
T* Ceil(T* ptr) const { |
||||||
|
uintptr_t intptr = reinterpret_cast<uintptr_t>(ptr); |
||||||
|
return reinterpret_cast<T*>((intptr + align - 1) & -align); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
T* CeilDefaultAligned(T* ptr) const { |
||||||
|
return Ceil(ArenaAlignDefault().CheckAligned(ptr)); |
||||||
|
} |
||||||
|
|
||||||
|
// Address sanitizer enabled alignment check
|
||||||
|
template <typename T> |
||||||
|
T* CheckAligned(T* ptr) const { |
||||||
|
GOOGLE_DCHECK(IsAligned(ptr)) << static_cast<void*>(ptr); |
||||||
|
return ptr; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
inline ArenaAlign ArenaAlignAs(size_t align) { |
||||||
|
// align must be a non zero power of 2 >= 8
|
||||||
|
GOOGLE_DCHECK_NE(align, 0); |
||||||
|
GOOGLE_DCHECK(absl::has_single_bit(align)) << "Invalid alignment " << align; |
||||||
|
return ArenaAlign{align}; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace protobuf
|
||||||
|
} // namespace google
|
||||||
|
|
||||||
|
#endif // GOOGLE_PROTOBUF_ARENA_ALIGN_H__
|
@ -0,0 +1,215 @@ |
|||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include "google/protobuf/arena_align.h" |
||||||
|
|
||||||
|
#include <gmock/gmock.h> |
||||||
|
#include <gtest/gtest.h> |
||||||
|
|
||||||
|
namespace google { |
||||||
|
namespace protobuf { |
||||||
|
namespace internal { |
||||||
|
namespace { |
||||||
|
|
||||||
|
using ::testing::Eq; |
||||||
|
|
||||||
|
TEST(ArenaAlignDefault, Align) { |
||||||
|
auto align_default = ArenaAlignDefault(); |
||||||
|
EXPECT_THAT(align_default.align, Eq(8)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(ArenaAlignDefault, Floor) { |
||||||
|
auto align_default = ArenaAlignDefault(); |
||||||
|
EXPECT_THAT(align_default.Floor(0), Eq(0)); |
||||||
|
EXPECT_THAT(align_default.Floor(1), Eq(0)); |
||||||
|
EXPECT_THAT(align_default.Floor(7), Eq(0)); |
||||||
|
EXPECT_THAT(align_default.Floor(8), Eq(8)); |
||||||
|
EXPECT_THAT(align_default.Floor(9), Eq(8)); |
||||||
|
EXPECT_THAT(align_default.Floor(15), Eq(8)); |
||||||
|
EXPECT_THAT(align_default.Floor(16), Eq(16)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(ArenaAlignDefault, Ceil) { |
||||||
|
auto align_default = ArenaAlignDefault(); |
||||||
|
EXPECT_THAT(align_default.Ceil(0), Eq(0)); |
||||||
|
EXPECT_THAT(align_default.Ceil(1), Eq(8)); |
||||||
|
EXPECT_THAT(align_default.Ceil(7), Eq(8)); |
||||||
|
EXPECT_THAT(align_default.Ceil(8), Eq(8)); |
||||||
|
EXPECT_THAT(align_default.Ceil(9), Eq(16)); |
||||||
|
EXPECT_THAT(align_default.Ceil(15), Eq(16)); |
||||||
|
EXPECT_THAT(align_default.Ceil(16), Eq(16)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(ArenaAlignDefault, CeilPtr) { |
||||||
|
char p[17] = {0}; |
||||||
|
auto align_default = ArenaAlignDefault(); |
||||||
|
EXPECT_THAT(align_default.Ceil(p + 0), Eq(p + 0)); |
||||||
|
EXPECT_THAT(align_default.Ceil(p + 1), Eq(p + 8)); |
||||||
|
EXPECT_THAT(align_default.Ceil(p + 7), Eq(p + 8)); |
||||||
|
EXPECT_THAT(align_default.Ceil(p + 8), Eq(p + 8)); |
||||||
|
EXPECT_THAT(align_default.Ceil(p + 9), Eq(p + 16)); |
||||||
|
EXPECT_THAT(align_default.Ceil(p + 15), Eq(p + 16)); |
||||||
|
EXPECT_THAT(align_default.Ceil(p + 16), Eq(p + 16)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(ArenaAlignDefault, CheckAligned) { |
||||||
|
char p[17] = {0}; |
||||||
|
auto align_default = ArenaAlignDefault(); |
||||||
|
EXPECT_THAT(align_default.CheckAligned(p + 0), Eq(p + 0)); |
||||||
|
EXPECT_THAT(align_default.CheckAligned(p + 8), Eq(p + 8)); |
||||||
|
EXPECT_THAT(align_default.CheckAligned(p + 16), Eq(p + 16)); |
||||||
|
#ifdef PROTOBUF_HAS_DEATH_TEST |
||||||
|
EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 1), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 7), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 9), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 15), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 17), ".*"); |
||||||
|
#endif // PROTOBUF_HAS_DEATH_TEST
|
||||||
|
} |
||||||
|
|
||||||
|
TEST(ArenaAlignDefault, CeilDefaultAligned) { |
||||||
|
char p[17] = {0}; |
||||||
|
auto align_default = ArenaAlignDefault(); |
||||||
|
EXPECT_THAT(align_default.CeilDefaultAligned(p + 0), Eq(p + 0)); |
||||||
|
EXPECT_THAT(align_default.CeilDefaultAligned(p + 8), Eq(p + 8)); |
||||||
|
EXPECT_THAT(align_default.CeilDefaultAligned(p + 16), Eq(p + 16)); |
||||||
|
#ifdef PROTOBUF_HAS_DEATH_TEST |
||||||
|
EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 1), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 7), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 9), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 15), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 17), ".*"); |
||||||
|
#endif // PROTOBUF_HAS_DEATH_TEST
|
||||||
|
} |
||||||
|
|
||||||
|
TEST(ArenaAlignDefault, IsAligned) { |
||||||
|
auto align_default = ArenaAlignDefault(); |
||||||
|
EXPECT_TRUE(align_default.IsAligned(0)); |
||||||
|
EXPECT_FALSE(align_default.IsAligned(1)); |
||||||
|
EXPECT_FALSE(align_default.IsAligned(7)); |
||||||
|
EXPECT_TRUE(align_default.IsAligned(8)); |
||||||
|
EXPECT_FALSE(align_default.IsAligned(9)); |
||||||
|
EXPECT_FALSE(align_default.IsAligned(15)); |
||||||
|
EXPECT_TRUE(align_default.IsAligned(16)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(ArenaAlign, Align) { |
||||||
|
auto align_64 = ArenaAlignAs(64); |
||||||
|
EXPECT_THAT(align_64.align, Eq(64)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(ArenaAlign, Floor) { |
||||||
|
auto align_64 = ArenaAlignAs(64); |
||||||
|
EXPECT_THAT(align_64.Floor(0), Eq(0)); |
||||||
|
EXPECT_THAT(align_64.Floor(1), Eq(0)); |
||||||
|
EXPECT_THAT(align_64.Floor(63), Eq(0)); |
||||||
|
EXPECT_THAT(align_64.Floor(64), Eq(64)); |
||||||
|
EXPECT_THAT(align_64.Floor(65), Eq(64)); |
||||||
|
EXPECT_THAT(align_64.Floor(127), Eq(64)); |
||||||
|
EXPECT_THAT(align_64.Floor(128), Eq(128)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(ArenaAlign, Ceil) { |
||||||
|
auto align_64 = ArenaAlignAs(64); |
||||||
|
EXPECT_THAT(align_64.Ceil(0), Eq(0)); |
||||||
|
EXPECT_THAT(align_64.Ceil(1), Eq(64)); |
||||||
|
EXPECT_THAT(align_64.Ceil(63), Eq(64)); |
||||||
|
EXPECT_THAT(align_64.Ceil(64), Eq(64)); |
||||||
|
EXPECT_THAT(align_64.Ceil(65), Eq(128)); |
||||||
|
EXPECT_THAT(align_64.Ceil(127), Eq(128)); |
||||||
|
EXPECT_THAT(align_64.Ceil(128), Eq(128)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(ArenaAlign, CeilPtr) { |
||||||
|
alignas(64) char p[129] = {0}; |
||||||
|
auto align_64 = ArenaAlignAs(64); |
||||||
|
EXPECT_THAT(align_64.Ceil(p + 0), Eq(p)); |
||||||
|
EXPECT_THAT(align_64.Ceil(p + 1), Eq(p + 64)); |
||||||
|
EXPECT_THAT(align_64.Ceil(p + 63), Eq(p + 64)); |
||||||
|
EXPECT_THAT(align_64.Ceil(p + 64), Eq(p + 64)); |
||||||
|
EXPECT_THAT(align_64.Ceil(p + 65), Eq(p + 128)); |
||||||
|
EXPECT_THAT(align_64.Ceil(p + 127), Eq(p + 128)); |
||||||
|
EXPECT_THAT(align_64.Ceil(p + 128), Eq(p + 128)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(ArenaAlign, CheckAligned) { |
||||||
|
alignas(128) char p[129] = {0}; |
||||||
|
auto align_64 = ArenaAlignAs(64); |
||||||
|
EXPECT_THAT(align_64.CheckAligned(p + 0), Eq(p)); |
||||||
|
EXPECT_THAT(align_64.CheckAligned(p + 64), Eq(p + 64)); |
||||||
|
EXPECT_THAT(align_64.CheckAligned(p + 128), Eq(p + 128)); |
||||||
|
#ifdef PROTOBUF_HAS_DEATH_TEST |
||||||
|
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 1), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 7), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 8), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 56), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 63), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 65), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 72), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 120), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 129), ".*"); |
||||||
|
#endif // PROTOBUF_HAS_DEATH_TEST
|
||||||
|
} |
||||||
|
|
||||||
|
TEST(ArenaAlign, CeilDefaultAligned) { |
||||||
|
alignas(128) char p[129] = {0}; |
||||||
|
auto align_64 = ArenaAlignAs(64); |
||||||
|
EXPECT_THAT(align_64.CeilDefaultAligned(p + 0), Eq(p)); |
||||||
|
EXPECT_THAT(align_64.CeilDefaultAligned(p + 8), Eq(p + 64)); |
||||||
|
EXPECT_THAT(align_64.CeilDefaultAligned(p + 56), Eq(p + 64)); |
||||||
|
EXPECT_THAT(align_64.CeilDefaultAligned(p + 64), Eq(p + 64)); |
||||||
|
EXPECT_THAT(align_64.CeilDefaultAligned(p + 72), Eq(p + 128)); |
||||||
|
EXPECT_THAT(align_64.CeilDefaultAligned(p + 120), Eq(p + 128)); |
||||||
|
EXPECT_THAT(align_64.CeilDefaultAligned(p + 128), Eq(p + 128)); |
||||||
|
#ifdef PROTOBUF_HAS_DEATH_TEST |
||||||
|
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 1), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 7), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 63), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 65), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 127), ".*"); |
||||||
|
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 129), ".*"); |
||||||
|
#endif // PROTOBUF_HAS_DEATH_TEST
|
||||||
|
} |
||||||
|
|
||||||
|
TEST(ArenaAlign, IsAligned) { |
||||||
|
auto align_64 = ArenaAlignAs(64); |
||||||
|
EXPECT_TRUE(align_64.IsAligned(0)); |
||||||
|
EXPECT_FALSE(align_64.IsAligned(1)); |
||||||
|
EXPECT_FALSE(align_64.IsAligned(63)); |
||||||
|
EXPECT_TRUE(align_64.IsAligned(64)); |
||||||
|
EXPECT_FALSE(align_64.IsAligned(65)); |
||||||
|
EXPECT_FALSE(align_64.IsAligned(127)); |
||||||
|
EXPECT_TRUE(align_64.IsAligned(128)); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace protobuf
|
||||||
|
} // namespace google
|
@ -0,0 +1,126 @@ |
|||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#ifndef GOOGLE_PROTOBUF_ARENA_ALLOCATION_POLICY_H__ |
||||||
|
#define GOOGLE_PROTOBUF_ARENA_ALLOCATION_POLICY_H__ |
||||||
|
|
||||||
|
#include <cstddef> |
||||||
|
#include <cstdint> |
||||||
|
|
||||||
|
#include "google/protobuf/arena_config.h" |
||||||
|
|
||||||
|
namespace google { |
||||||
|
namespace protobuf { |
||||||
|
namespace internal { |
||||||
|
|
||||||
|
// `AllocationPolicy` defines `Arena` allocation policies. Applications can
|
||||||
|
// customize the inital and maximum sizes for arena allocation, as well as set
|
||||||
|
// custom allocation and deallocation functions. `AllocationPolicy` is for
|
||||||
|
// protocol buffer internal use only, and typically created from a user facing
|
||||||
|
// public configuration class such as `ArenaOptions`.
|
||||||
|
struct AllocationPolicy { |
||||||
|
static constexpr size_t kDefaultStartBlockSize = 256; |
||||||
|
|
||||||
|
size_t start_block_size = kDefaultStartBlockSize; |
||||||
|
size_t max_block_size = GetDefaultArenaMaxBlockSize(); |
||||||
|
|
||||||
|
void* (*block_alloc)(size_t) = nullptr; |
||||||
|
void (*block_dealloc)(void*, size_t) = nullptr; |
||||||
|
|
||||||
|
bool IsDefault() const { |
||||||
|
return start_block_size == kDefaultStartBlockSize && |
||||||
|
max_block_size == GetDefaultArenaMaxBlockSize() && |
||||||
|
block_alloc == nullptr && block_dealloc == nullptr; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
// Tagged pointer to an AllocationPolicy.
|
||||||
|
class TaggedAllocationPolicyPtr { |
||||||
|
public: |
||||||
|
constexpr TaggedAllocationPolicyPtr() : policy_(0) {} |
||||||
|
|
||||||
|
explicit TaggedAllocationPolicyPtr(AllocationPolicy* policy) |
||||||
|
: policy_(reinterpret_cast<uintptr_t>(policy)) {} |
||||||
|
|
||||||
|
void set_policy(AllocationPolicy* policy) { |
||||||
|
auto bits = policy_ & kTagsMask; |
||||||
|
policy_ = reinterpret_cast<uintptr_t>(policy) | bits; |
||||||
|
} |
||||||
|
|
||||||
|
AllocationPolicy* get() { |
||||||
|
return reinterpret_cast<AllocationPolicy*>(policy_ & kPtrMask); |
||||||
|
} |
||||||
|
const AllocationPolicy* get() const { |
||||||
|
return reinterpret_cast<const AllocationPolicy*>(policy_ & kPtrMask); |
||||||
|
} |
||||||
|
|
||||||
|
AllocationPolicy& operator*() { return *get(); } |
||||||
|
const AllocationPolicy& operator*() const { return *get(); } |
||||||
|
|
||||||
|
AllocationPolicy* operator->() { return get(); } |
||||||
|
const AllocationPolicy* operator->() const { return get(); } |
||||||
|
|
||||||
|
bool is_user_owned_initial_block() const { |
||||||
|
return static_cast<bool>(get_mask<kUserOwnedInitialBlock>()); |
||||||
|
} |
||||||
|
void set_is_user_owned_initial_block(bool v) { |
||||||
|
set_mask<kUserOwnedInitialBlock>(v); |
||||||
|
} |
||||||
|
|
||||||
|
uintptr_t get_raw() const { return policy_; } |
||||||
|
|
||||||
|
private: |
||||||
|
enum : uintptr_t { |
||||||
|
kUserOwnedInitialBlock = 1, |
||||||
|
}; |
||||||
|
|
||||||
|
static constexpr uintptr_t kTagsMask = 7; |
||||||
|
static constexpr uintptr_t kPtrMask = ~kTagsMask; |
||||||
|
|
||||||
|
template <uintptr_t kMask> |
||||||
|
uintptr_t get_mask() const { |
||||||
|
return policy_ & kMask; |
||||||
|
} |
||||||
|
template <uintptr_t kMask> |
||||||
|
void set_mask(bool v) { |
||||||
|
if (v) { |
||||||
|
policy_ |= kMask; |
||||||
|
} else { |
||||||
|
policy_ &= ~kMask; |
||||||
|
} |
||||||
|
} |
||||||
|
uintptr_t policy_; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace protobuf
|
||||||
|
} // namespace google
|
||||||
|
|
||||||
|
#endif // GOOGLE_PROTOBUF_ARENA_ALLOCATION_POLICY_H__
|
@ -0,0 +1,189 @@ |
|||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#ifndef GOOGLE_PROTOBUF_ARENA_CLEANUP_H__ |
||||||
|
#define GOOGLE_PROTOBUF_ARENA_CLEANUP_H__ |
||||||
|
|
||||||
|
#include <cstddef> |
||||||
|
#include <cstdint> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include "google/protobuf/stubs/logging.h" |
||||||
|
#include "google/protobuf/stubs/common.h" |
||||||
|
#include "absl/base/attributes.h" |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace google { |
||||||
|
namespace protobuf { |
||||||
|
namespace internal { |
||||||
|
namespace cleanup { |
||||||
|
|
||||||
|
// Helper function invoking the destructor of `object`
|
||||||
|
template <typename T> |
||||||
|
void arena_destruct_object(void* object) { |
||||||
|
reinterpret_cast<T*>(object)->~T(); |
||||||
|
} |
||||||
|
|
||||||
|
// Tag defines the type of cleanup / cleanup object. This tag is stored in the
|
||||||
|
// lowest 2 bits of the `elem` value identifying the type of node. All node
|
||||||
|
// types must start with a `uintptr_t` that stores `Tag` in its low two bits.
|
||||||
|
enum class Tag : uintptr_t { |
||||||
|
kDynamic = 0, // DynamicNode
|
||||||
|
kString = 1, // StringNode (std::string)
|
||||||
|
}; |
||||||
|
|
||||||
|
// DynamicNode contains the object (`elem`) that needs to be
|
||||||
|
// destroyed, and the function to destroy it (`destructor`)
|
||||||
|
// elem must be aligned at minimum on a 4 byte boundary.
|
||||||
|
struct DynamicNode { |
||||||
|
uintptr_t elem; |
||||||
|
void (*destructor)(void*); |
||||||
|
}; |
||||||
|
|
||||||
|
// StringNode contains a `std::string` object (`elem`) that needs to be
|
||||||
|
// destroyed. The lowest 2 bits of `elem` contain the non-zero kString tag.
|
||||||
|
struct StringNode { |
||||||
|
uintptr_t elem; |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
// EnableSpecializedTags() return true if the alignment of tagged objects
|
||||||
|
// such as std::string allow us to poke tags in the 2 LSB bits.
|
||||||
|
inline constexpr bool EnableSpecializedTags() { |
||||||
|
// For now we require 2 bits
|
||||||
|
return alignof(std::string) >= 8; |
||||||
|
} |
||||||
|
|
||||||
|
// Adds a cleanup entry identified by `tag` at memory location `pos`.
|
||||||
|
inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CreateNode(Tag tag, void* pos, |
||||||
|
const void* elem_raw, |
||||||
|
void (*destructor)(void*)) { |
||||||
|
auto elem = reinterpret_cast<uintptr_t>(elem_raw); |
||||||
|
if (EnableSpecializedTags()) { |
||||||
|
GOOGLE_DCHECK_EQ(elem & 3, 0ULL); // Must be aligned
|
||||||
|
switch (tag) { |
||||||
|
case Tag::kString: { |
||||||
|
StringNode n = {elem | static_cast<uintptr_t>(Tag::kString)}; |
||||||
|
memcpy(pos, &n, sizeof(n)); |
||||||
|
return; |
||||||
|
} |
||||||
|
default: |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
DynamicNode n = {elem, destructor}; |
||||||
|
memcpy(pos, &n, sizeof(n)); |
||||||
|
} |
||||||
|
|
||||||
|
// Optimization: performs a prefetch on `elem_address`.
|
||||||
|
inline ABSL_ATTRIBUTE_ALWAYS_INLINE void PrefetchNode( |
||||||
|
const void* elem_address) { |
||||||
|
(void)elem_address; |
||||||
|
} |
||||||
|
|
||||||
|
// Destroys the node idenitfied by `tag` stored at memory location `pos`.
|
||||||
|
inline ABSL_ATTRIBUTE_ALWAYS_INLINE void DestroyNode(Tag tag, const void* pos) { |
||||||
|
if (EnableSpecializedTags()) { |
||||||
|
switch (tag) { |
||||||
|
case Tag::kString: { |
||||||
|
StringNode n; |
||||||
|
memcpy(&n, pos, sizeof(n)); |
||||||
|
auto* s = reinterpret_cast<std::string*>(n.elem & ~0x7ULL); |
||||||
|
// Some compilers don't like fully qualified explicit dtor calls,
|
||||||
|
// so use an alias to avoid having to type `::`.
|
||||||
|
using string_type = std::string; |
||||||
|
s->~string_type(); |
||||||
|
return; |
||||||
|
} |
||||||
|
default: |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
DynamicNode n; |
||||||
|
memcpy(&n, pos, sizeof(n)); |
||||||
|
n.destructor(reinterpret_cast<void*>(n.elem)); |
||||||
|
} |
||||||
|
|
||||||
|
// Returns the `tag` identifying the type of object for `destructor` or
|
||||||
|
// kDynamic if `destructor` does not identify a well know object type.
|
||||||
|
inline ABSL_ATTRIBUTE_ALWAYS_INLINE Tag Type(void (*destructor)(void*)) { |
||||||
|
if (EnableSpecializedTags()) { |
||||||
|
if (destructor == &arena_destruct_object<std::string>) { |
||||||
|
return Tag::kString; |
||||||
|
} |
||||||
|
} |
||||||
|
return Tag::kDynamic; |
||||||
|
} |
||||||
|
|
||||||
|
// Returns the `tag` identifying the type of object stored at memory location
|
||||||
|
// `elem`, which represents the first uintptr_t value in the node.
|
||||||
|
inline ABSL_ATTRIBUTE_ALWAYS_INLINE Tag Type(void* raw) { |
||||||
|
if (!EnableSpecializedTags()) return Tag::kDynamic; |
||||||
|
|
||||||
|
uintptr_t elem; |
||||||
|
memcpy(&elem, raw, sizeof(elem)); |
||||||
|
switch (static_cast<Tag>(elem & 0x7ULL)) { |
||||||
|
case Tag::kDynamic: |
||||||
|
return Tag::kDynamic; |
||||||
|
case Tag::kString: |
||||||
|
return Tag::kString; |
||||||
|
default: |
||||||
|
GOOGLE_LOG(FATAL) << "Corrupted cleanup tag: " << (elem & 0x7ULL); |
||||||
|
return Tag::kDynamic; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Returns the required size in bytes off the node type identified by `tag`.
|
||||||
|
inline ABSL_ATTRIBUTE_ALWAYS_INLINE size_t Size(Tag tag) { |
||||||
|
if (!EnableSpecializedTags()) return sizeof(DynamicNode); |
||||||
|
|
||||||
|
switch (tag) { |
||||||
|
case Tag::kDynamic: |
||||||
|
return sizeof(DynamicNode); |
||||||
|
case Tag::kString: |
||||||
|
return sizeof(StringNode); |
||||||
|
default: |
||||||
|
GOOGLE_LOG(FATAL) << "Corrupted cleanup tag: " << static_cast<int>(tag); |
||||||
|
return sizeof(DynamicNode); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Returns the required size in bytes off the node type for `destructor`.
|
||||||
|
inline ABSL_ATTRIBUTE_ALWAYS_INLINE size_t Size(void (*destructor)(void*)) { |
||||||
|
return destructor == nullptr ? 0 : Size(Type(destructor)); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace cleanup
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace protobuf
|
||||||
|
} // namespace google
|
||||||
|
|
||||||
|
#endif // GOOGLE_PROTOBUF_ARENA_CLEANUP_H__
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue