PiperOrigin-RevId: 647378884pull/17239/head
parent
dfe3300c2f
commit
d7087fc901
24 changed files with 2252 additions and 1541 deletions
@ -0,0 +1,184 @@ |
||||
# Copyright (c) 2009-2021, Google LLC |
||||
# All rights reserved. |
||||
# |
||||
# Use of this source code is governed by a BSD-style |
||||
# license that can be found in the LICENSE file or at |
||||
# https://developers.google.com/open-source/licenses/bsd |
||||
|
||||
load( |
||||
"//hpb/bazel:upb_cc_proto_library.bzl", |
||||
"upb_cc_proto_library_copts", |
||||
) |
||||
load( |
||||
"//upb/bazel:build_defs.bzl", |
||||
"UPB_DEFAULT_CPPOPTS", |
||||
) |
||||
|
||||
# begin:google_only |
||||
# package(default_applicable_licenses = ["//upb:license"]) |
||||
# end:google_only |
||||
|
||||
licenses(["notice"]) |
||||
|
||||
cc_library( |
||||
name = "repeated_field", |
||||
hdrs = [ |
||||
"repeated_field.h", |
||||
"repeated_field_iterator.h", |
||||
], |
||||
compatible_with = ["//buildenv/target:non_prod"], |
||||
copts = UPB_DEFAULT_CPPOPTS, |
||||
visibility = ["//visibility:public"], |
||||
deps = [ |
||||
":hpb", |
||||
":protos_traits", |
||||
"//upb:base", |
||||
"//upb:mem", |
||||
"//upb:message", |
||||
"//upb:message_copy", |
||||
"@com_google_absl//absl/base:core_headers", |
||||
"@com_google_absl//absl/strings", |
||||
], |
||||
) |
||||
|
||||
cc_library( |
||||
name = "hpb", |
||||
srcs = [ |
||||
"protos.cc", |
||||
], |
||||
hdrs = [ |
||||
"protos.h", |
||||
], |
||||
compatible_with = ["//buildenv/target:non_prod"], |
||||
copts = UPB_DEFAULT_CPPOPTS, |
||||
visibility = ["//visibility:public"], |
||||
deps = [ |
||||
":protos_extension_lock", |
||||
"//upb:base", |
||||
"//upb:mem", |
||||
"//upb:message", |
||||
"//upb:message_copy", |
||||
"//upb:message_promote", |
||||
"//upb:mini_table", |
||||
"//upb:wire", |
||||
"//upb:wire_reader", |
||||
"@com_google_absl//absl/status", |
||||
"@com_google_absl//absl/status:statusor", |
||||
"@com_google_absl//absl/strings", |
||||
"@com_google_absl//absl/strings:str_format", |
||||
], |
||||
) |
||||
|
||||
# Internally used type traits. |
||||
cc_library( |
||||
name = "protos_traits", |
||||
hdrs = [ |
||||
"protos_traits.h", |
||||
], |
||||
compatible_with = ["//buildenv/target:non_prod"], |
||||
copts = UPB_DEFAULT_CPPOPTS, |
||||
# TODO: update visibility back to private once upb/protos gets removed |
||||
visibility = ["//protos:__subpackages__"], |
||||
) |
||||
|
||||
cc_library( |
||||
name = "protos_internal", |
||||
hdrs = ["protos_internal.h"], |
||||
compatible_with = ["//buildenv/target:non_prod"], |
||||
copts = UPB_DEFAULT_CPPOPTS, |
||||
visibility = ["//upb:friends"], |
||||
deps = [ |
||||
":hpb", |
||||
"//upb:mem", |
||||
"//upb:message", |
||||
"//upb:mini_table", |
||||
"@com_google_absl//absl/status", |
||||
"@com_google_absl//absl/status:statusor", |
||||
"@com_google_absl//absl/strings:str_format", |
||||
], |
||||
) |
||||
|
||||
cc_library( |
||||
name = "protos_extension_lock", |
||||
srcs = ["protos_extension_lock.cc"], |
||||
hdrs = [ |
||||
"protos_extension_lock.h", |
||||
], |
||||
compatible_with = ["//buildenv/target:non_prod"], |
||||
copts = UPB_DEFAULT_CPPOPTS, |
||||
visibility = ["//upb:friends"], |
||||
deps = [ |
||||
"//upb:message", |
||||
"@com_google_absl//absl/base:core_headers", |
||||
"@com_google_absl//absl/synchronization", |
||||
], |
||||
) |
||||
|
||||
# Common support code for C++ generated code. |
||||
cc_library( |
||||
name = "generated_protos_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me", |
||||
hdrs = [ |
||||
"protos_internal.h", |
||||
], |
||||
compatible_with = ["//buildenv/target:non_prod"], |
||||
copts = UPB_DEFAULT_CPPOPTS, |
||||
visibility = ["//visibility:public"], |
||||
deps = [ |
||||
":hpb", |
||||
":protos_internal", |
||||
":repeated_field", |
||||
"//upb:mem", |
||||
"//upb:message", |
||||
], |
||||
) |
||||
|
||||
cc_test( |
||||
name = "protos_internal_test", |
||||
srcs = ["protos_internal_test.cc"], |
||||
copts = UPB_DEFAULT_CPPOPTS, |
||||
deps = [ |
||||
":protos_internal", |
||||
"//hpb_generator/tests:test_model_upb_cc_proto", |
||||
"//hpb_generator/tests:test_model_upb_proto", |
||||
"//upb:mem", |
||||
"@com_google_googletest//:gtest", |
||||
"@com_google_googletest//:gtest_main", |
||||
], |
||||
) |
||||
|
||||
upb_cc_proto_library_copts( |
||||
name = "upb_cc_proto_library_copts__for_generated_code_only_do_not_use", |
||||
copts = UPB_DEFAULT_CPPOPTS, |
||||
visibility = ["//visibility:public"], |
||||
) |
||||
|
||||
cc_test( |
||||
name = "repeated_field_iterator_test", |
||||
srcs = ["repeated_field_iterator_test.cc"], |
||||
deps = [ |
||||
":repeated_field", |
||||
"@com_google_googletest//:gtest", |
||||
"@com_google_googletest//:gtest_main", |
||||
], |
||||
) |
||||
|
||||
cc_test( |
||||
name = "protos_extension_lock_test", |
||||
srcs = ["protos_extension_lock_test.cc"], |
||||
deps = [ |
||||
"//hpb", |
||||
"//hpb:protos_extension_lock", |
||||
"//hpb_generator/tests:test_model_upb_cc_proto", |
||||
"//upb:mem", |
||||
"@com_google_absl//absl/hash", |
||||
"@com_google_absl//absl/log:absl_check", |
||||
"@com_google_googletest//:gtest", |
||||
"@com_google_googletest//:gtest_main", |
||||
], |
||||
) |
||||
|
||||
cc_library( |
||||
name = "requires", |
||||
hdrs = ["requires.h"], |
||||
visibility = ["//visibility:public"], |
||||
) |
@ -0,0 +1,25 @@ |
||||
# Copyright (c) 2009-2021, Google LLC |
||||
# All rights reserved. |
||||
# |
||||
# Use of this source code is governed by a BSD-style |
||||
# license that can be found in the LICENSE file or at |
||||
# https://developers.google.com/open-source/licenses/bsd |
||||
|
||||
load("@bazel_skylib//:bzl_library.bzl", "bzl_library") |
||||
|
||||
# begin:google_only |
||||
# package(default_applicable_licenses = ["//upb:license"]) |
||||
# end:google_only |
||||
|
||||
licenses(["notice"]) |
||||
|
||||
bzl_library( |
||||
name = "upb_cc_proto_library_bzl", |
||||
srcs = ["upb_cc_proto_library.bzl"], |
||||
visibility = ["//visibility:public"], |
||||
deps = [ |
||||
"//bazel:upb_proto_library_bzl", |
||||
"@bazel_skylib//lib:paths", |
||||
"@bazel_tools//tools/cpp:toolchain_utils.bzl", |
||||
], |
||||
) |
@ -0,0 +1,293 @@ |
||||
# Copyright (c) 2009-2021, Google LLC |
||||
# All rights reserved. |
||||
# |
||||
# Use of this source code is governed by a BSD-style |
||||
# license that can be found in the LICENSE file or at |
||||
# https://developers.google.com/open-source/licenses/bsd |
||||
|
||||
"""Public rules for using upb protos: |
||||
- upb_cc_proto_library() |
||||
""" |
||||
|
||||
load("@bazel_skylib//lib:paths.bzl", "paths") |
||||
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain") |
||||
load("//bazel:upb_proto_library.bzl", "GeneratedSrcsInfo", "UpbWrappedCcInfo", "upb_proto_library_aspect") |
||||
|
||||
# begin:google_only |
||||
# |
||||
# def upb_use_cpp_toolchain(): |
||||
# # TODO: We shouldn't need to add this to the result of use_cpp_toolchain(). |
||||
# return [ |
||||
# config_common.toolchain_type( |
||||
# "@bazel_tools//tools/cpp:cc_runtimes_toolchain_type", |
||||
# mandatory = False, |
||||
# ), |
||||
# ] + use_cpp_toolchain() |
||||
# |
||||
# end:google_only |
||||
|
||||
# begin:github_only |
||||
def upb_use_cpp_toolchain(): |
||||
return use_cpp_toolchain() |
||||
|
||||
# end:github_only |
||||
|
||||
# Generic support code ######################################################### |
||||
|
||||
def _get_real_short_path(file): |
||||
# For some reason, files from other archives have short paths that look like: |
||||
# ../com_google_protobuf/google/protobuf/descriptor.proto |
||||
short_path = file.short_path |
||||
if short_path.startswith("../"): |
||||
second_slash = short_path.index("/", 3) |
||||
short_path = short_path[second_slash + 1:] |
||||
|
||||
# Sometimes it has another few prefixes like: |
||||
# _virtual_imports/any_proto/google/protobuf/any.proto |
||||
# benchmarks/_virtual_imports/100_msgs_proto/benchmarks/100_msgs.proto |
||||
# We want just google/protobuf/any.proto. |
||||
virtual_imports = "_virtual_imports/" |
||||
if virtual_imports in short_path: |
||||
short_path = short_path.split(virtual_imports)[1].split("/", 1)[1] |
||||
return short_path |
||||
|
||||
def _get_real_root(file): |
||||
real_short_path = _get_real_short_path(file) |
||||
return file.path[:-len(real_short_path) - 1] |
||||
|
||||
def _generate_output_file(ctx, src, extension): |
||||
real_short_path = _get_real_short_path(src) |
||||
real_short_path = paths.relativize(real_short_path, ctx.label.package) |
||||
output_filename = paths.replace_extension(real_short_path, extension) |
||||
ret = ctx.actions.declare_file(output_filename) |
||||
return ret |
||||
|
||||
def _filter_none(elems): |
||||
return [e for e in elems if e] |
||||
|
||||
def _cc_library_func(ctx, name, hdrs, srcs, copts, dep_ccinfos): |
||||
"""Like cc_library(), but callable from rules. |
||||
|
||||
Args: |
||||
ctx: Rule context. |
||||
name: Unique name used to generate output files. |
||||
hdrs: Public headers that can be #included from other rules. |
||||
srcs: C/C++ source files. |
||||
copts: Additional options for cc compilation. |
||||
dep_ccinfos: CcInfo providers of dependencies we should build/link against. |
||||
|
||||
Returns: |
||||
CcInfo provider for this compilation. |
||||
""" |
||||
|
||||
# begin:google_only |
||||
# cc_runtimes_toolchain = ctx.toolchains["@bazel_tools//tools/cpp:cc_runtimes_toolchain_type"] |
||||
# if cc_runtimes_toolchain: |
||||
# dep_ccinfos += [ |
||||
# target[CcInfo] |
||||
# for target in cc_runtimes_toolchain.cc_runtimes_info.runtimes |
||||
# ] |
||||
# |
||||
# end:google_only |
||||
|
||||
compilation_contexts = [info.compilation_context for info in dep_ccinfos] |
||||
linking_contexts = [info.linking_context for info in dep_ccinfos] |
||||
toolchain = find_cpp_toolchain(ctx) |
||||
feature_configuration = cc_common.configure_features( |
||||
ctx = ctx, |
||||
cc_toolchain = toolchain, |
||||
requested_features = ctx.features, |
||||
unsupported_features = ctx.disabled_features, |
||||
) |
||||
|
||||
(compilation_context, compilation_outputs) = cc_common.compile( |
||||
actions = ctx.actions, |
||||
feature_configuration = feature_configuration, |
||||
cc_toolchain = toolchain, |
||||
name = name, |
||||
srcs = srcs, |
||||
public_hdrs = hdrs, |
||||
user_compile_flags = copts, |
||||
compilation_contexts = compilation_contexts, |
||||
) |
||||
|
||||
# buildifier: disable=unused-variable |
||||
(linking_context, linking_outputs) = cc_common.create_linking_context_from_compilation_outputs( |
||||
actions = ctx.actions, |
||||
name = name, |
||||
feature_configuration = feature_configuration, |
||||
cc_toolchain = toolchain, |
||||
compilation_outputs = compilation_outputs, |
||||
linking_contexts = linking_contexts, |
||||
) |
||||
|
||||
return CcInfo( |
||||
compilation_context = compilation_context, |
||||
linking_context = linking_context, |
||||
) |
||||
|
||||
# Dummy rule to expose select() copts to aspects ############################## |
||||
|
||||
UpbCcProtoLibraryCoptsInfo = provider( |
||||
"Provides copts for upb cc proto targets", |
||||
fields = { |
||||
"copts": "copts for upb_cc_proto_library()", |
||||
}, |
||||
) |
||||
|
||||
def upb_cc_proto_library_copts_impl(ctx): |
||||
return UpbCcProtoLibraryCoptsInfo(copts = ctx.attr.copts) |
||||
|
||||
upb_cc_proto_library_copts = rule( |
||||
implementation = upb_cc_proto_library_copts_impl, |
||||
attrs = {"copts": attr.string_list(default = [])}, |
||||
) |
||||
|
||||
_UpbCcWrappedCcInfo = provider("Provider for cc_info for protos", fields = ["cc_info"]) |
||||
_WrappedCcGeneratedSrcsInfo = provider("Provider for generated sources", fields = ["srcs"]) |
||||
|
||||
def _compile_upb_cc_protos(ctx, generator, proto_info, proto_sources): |
||||
if len(proto_sources) == 0: |
||||
return GeneratedSrcsInfo(srcs = [], hdrs = []) |
||||
|
||||
tool = getattr(ctx.executable, "_gen_" + generator) |
||||
srcs = [_generate_output_file(ctx, name, ".upb.proto.cc") for name in proto_sources] |
||||
hdrs = [_generate_output_file(ctx, name, ".upb.proto.h") for name in proto_sources] |
||||
hdrs += [_generate_output_file(ctx, name, ".upb.fwd.h") for name in proto_sources] |
||||
transitive_sets = proto_info.transitive_descriptor_sets.to_list() |
||||
|
||||
args = ctx.actions.args() |
||||
args.use_param_file(param_file_arg = "@%s") |
||||
args.set_param_file_format("multiline") |
||||
|
||||
args.add("--" + generator + "_out=" + _get_real_root(srcs[0])) |
||||
args.add("--plugin=protoc-gen-" + generator + "=" + tool.path) |
||||
args.add("--descriptor_set_in=" + ctx.configuration.host_path_separator.join([f.path for f in transitive_sets])) |
||||
args.add_all(proto_sources, map_each = _get_real_short_path) |
||||
|
||||
ctx.actions.run( |
||||
inputs = depset( |
||||
direct = [proto_info.direct_descriptor_set], |
||||
transitive = [proto_info.transitive_descriptor_sets], |
||||
), |
||||
tools = [tool], |
||||
outputs = srcs + hdrs, |
||||
executable = ctx.executable._protoc, |
||||
arguments = [args], |
||||
progress_message = "Generating upb cc protos for :" + ctx.label.name, |
||||
) |
||||
return GeneratedSrcsInfo(srcs = srcs, hdrs = hdrs) |
||||
|
||||
def _upb_cc_proto_rule_impl(ctx): |
||||
if len(ctx.attr.deps) != 1: |
||||
fail("only one deps dependency allowed.") |
||||
dep = ctx.attr.deps[0] |
||||
|
||||
if _WrappedCcGeneratedSrcsInfo in dep: |
||||
srcs = dep[_WrappedCcGeneratedSrcsInfo].srcs |
||||
else: |
||||
fail("proto_library rule must generate _WrappedCcGeneratedSrcsInfo (aspect should have " + |
||||
"handled this).") |
||||
|
||||
if _UpbCcWrappedCcInfo in dep: |
||||
cc_info = dep[_UpbCcWrappedCcInfo].cc_info |
||||
elif UpbWrappedCcInfo in dep: |
||||
cc_info = dep[UpbWrappedCcInfo].cc_info |
||||
else: |
||||
fail("proto_library rule must generate UpbWrappedCcInfo or " + |
||||
"_UpbCcWrappedCcInfo (aspect should have handled this).") |
||||
|
||||
lib = cc_info.linking_context.linker_inputs.to_list()[0].libraries[0] |
||||
files = _filter_none([ |
||||
lib.static_library, |
||||
lib.pic_static_library, |
||||
lib.dynamic_library, |
||||
]) |
||||
return [ |
||||
DefaultInfo(files = depset(files + srcs.hdrs + srcs.srcs)), |
||||
srcs, |
||||
cc_info, |
||||
] |
||||
|
||||
def _upb_cc_proto_aspect_impl(target, ctx, generator, cc_provider, file_provider): |
||||
proto_info = target[ProtoInfo] |
||||
files = _compile_upb_cc_protos(ctx, generator, proto_info, proto_info.direct_sources) |
||||
deps = ctx.rule.attr.deps + getattr(ctx.attr, "_" + generator) |
||||
dep_ccinfos = [dep[CcInfo] for dep in deps if CcInfo in dep] |
||||
dep_ccinfos += [dep[UpbWrappedCcInfo].cc_info for dep in deps if UpbWrappedCcInfo in dep] |
||||
dep_ccinfos += [dep[_UpbCcWrappedCcInfo].cc_info for dep in deps if _UpbCcWrappedCcInfo in dep] |
||||
if UpbWrappedCcInfo not in target: |
||||
fail("Target should have UpbWrappedCcInfo provider") |
||||
dep_ccinfos.append(target[UpbWrappedCcInfo].cc_info) |
||||
cc_info = _cc_library_func( |
||||
ctx = ctx, |
||||
name = ctx.rule.attr.name + "." + generator, |
||||
hdrs = files.hdrs, |
||||
srcs = files.srcs, |
||||
copts = ctx.attr._ccopts[UpbCcProtoLibraryCoptsInfo].copts, |
||||
dep_ccinfos = dep_ccinfos, |
||||
) |
||||
return [cc_provider(cc_info = cc_info), file_provider(srcs = files)] |
||||
|
||||
def _upb_cc_proto_library_aspect_impl(target, ctx): |
||||
return _upb_cc_proto_aspect_impl(target, ctx, "upbprotos", _UpbCcWrappedCcInfo, _WrappedCcGeneratedSrcsInfo) |
||||
|
||||
_upb_cc_proto_library_aspect = aspect( |
||||
attrs = { |
||||
"_ccopts": attr.label( |
||||
default = "//protos:upb_cc_proto_library_copts__for_generated_code_only_do_not_use", |
||||
), |
||||
"_gen_upbprotos": attr.label( |
||||
executable = True, |
||||
cfg = "exec", |
||||
default = "//hpb_generator:protoc-gen-upb-protos", |
||||
), |
||||
"_protoc": attr.label( |
||||
executable = True, |
||||
cfg = "exec", |
||||
default = "//net/proto2/compiler/public:protocol_compiler", |
||||
), |
||||
"_cc_toolchain": attr.label( |
||||
default = "@bazel_tools//tools/cpp:current_cc_toolchain", |
||||
), |
||||
"_upbprotos": attr.label_list( |
||||
default = [ |
||||
# TODO: Add dependencies for cc runtime (absl/string etc..) |
||||
"//upb:generated_cpp_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me", |
||||
"//protos:generated_protos_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me", |
||||
"@com_google_absl//absl/strings", |
||||
"@com_google_absl//absl/status:statusor", |
||||
"//protos", |
||||
"//protos:repeated_field", |
||||
], |
||||
), |
||||
}, |
||||
implementation = _upb_cc_proto_library_aspect_impl, |
||||
provides = [ |
||||
_UpbCcWrappedCcInfo, |
||||
_WrappedCcGeneratedSrcsInfo, |
||||
], |
||||
required_aspect_providers = [ |
||||
UpbWrappedCcInfo, |
||||
], |
||||
attr_aspects = ["deps"], |
||||
fragments = ["cpp"], |
||||
toolchains = upb_use_cpp_toolchain(), |
||||
) |
||||
|
||||
upb_cc_proto_library = rule( |
||||
implementation = _upb_cc_proto_rule_impl, |
||||
attrs = { |
||||
"deps": attr.label_list( |
||||
aspects = [ |
||||
upb_proto_library_aspect, |
||||
_upb_cc_proto_library_aspect, |
||||
], |
||||
allow_rules = ["proto_library"], |
||||
providers = [ProtoInfo], |
||||
), |
||||
"_ccopts": attr.label( |
||||
default = "//protos:upb_cc_proto_library_copts__for_generated_code_only_do_not_use", |
||||
), |
||||
}, |
||||
) |
@ -0,0 +1,185 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google LLC. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include "google/protobuf/hpb/protos.h" |
||||
|
||||
#include <atomic> |
||||
#include <cstddef> |
||||
|
||||
#include "absl/status/status.h" |
||||
#include "absl/status/statusor.h" |
||||
#include "absl/strings/str_format.h" |
||||
#include "absl/strings/string_view.h" |
||||
#include "google/protobuf/hpb/protos_extension_lock.h" |
||||
#include "upb/mem/arena.h" |
||||
#include "upb/message/accessors.h" |
||||
#include "upb/message/copy.h" |
||||
#include "upb/message/message.h" |
||||
#include "upb/message/promote.h" |
||||
#include "upb/message/value.h" |
||||
#include "upb/mini_table/extension.h" |
||||
#include "upb/mini_table/extension_registry.h" |
||||
#include "upb/mini_table/message.h" |
||||
#include "upb/wire/decode.h" |
||||
#include "upb/wire/encode.h" |
||||
|
||||
namespace protos { |
||||
|
||||
// begin:google_only
|
||||
absl::Status MessageAllocationError(SourceLocation loc) { |
||||
return absl::Status(absl::StatusCode::kInternal, |
||||
"Upb message allocation error", loc); |
||||
} |
||||
|
||||
absl::Status ExtensionNotFoundError(int extension_number, SourceLocation loc) { |
||||
return absl::Status( |
||||
absl::StatusCode::kInternal, |
||||
absl::StrFormat("Extension %d not found", extension_number), loc); |
||||
} |
||||
|
||||
absl::Status MessageEncodeError(upb_EncodeStatus status, SourceLocation loc) { |
||||
return absl::Status(absl::StatusCode::kInternal, |
||||
absl::StrFormat("Upb message encoding error %d", status), |
||||
loc |
||||
|
||||
); |
||||
} |
||||
|
||||
absl::Status MessageDecodeError(upb_DecodeStatus status, SourceLocation loc |
||||
|
||||
) { |
||||
return absl::Status(absl::StatusCode::kInternal, |
||||
absl::StrFormat("Upb message parse error %d", status), loc |
||||
|
||||
); |
||||
} |
||||
// end:google_only
|
||||
|
||||
// begin:github_only
|
||||
// absl::Status MessageAllocationError(SourceLocation loc) {
|
||||
// return absl::Status(absl::StatusCode::kUnknown,
|
||||
// "Upb message allocation error");
|
||||
// }
|
||||
//
|
||||
// absl::Status ExtensionNotFoundError(int ext_number, SourceLocation loc) {
|
||||
// return absl::Status(absl::StatusCode::kUnknown,
|
||||
// absl::StrFormat("Extension %d not found", ext_number));
|
||||
// }
|
||||
//
|
||||
// absl::Status MessageEncodeError(upb_EncodeStatus s, SourceLocation loc) {
|
||||
// return absl::Status(absl::StatusCode::kUnknown, "Encoding error");
|
||||
// }
|
||||
//
|
||||
// absl::Status MessageDecodeError(upb_DecodeStatus status, SourceLocation loc
|
||||
//
|
||||
// ) {
|
||||
// return absl::Status(absl::StatusCode::kUnknown, "Upb message parse error");
|
||||
// }
|
||||
// end:github_only
|
||||
|
||||
namespace internal { |
||||
|
||||
upb_ExtensionRegistry* GetUpbExtensions( |
||||
const ExtensionRegistry& extension_registry) { |
||||
return extension_registry.registry_; |
||||
} |
||||
|
||||
/**
|
||||
* MessageLock(msg) acquires lock on msg when constructed and releases it when |
||||
* destroyed. |
||||
*/ |
||||
class MessageLock { |
||||
public: |
||||
explicit MessageLock(const upb_Message* msg) : msg_(msg) { |
||||
UpbExtensionLocker locker = |
||||
upb_extension_locker_global.load(std::memory_order_acquire); |
||||
unlocker_ = (locker != nullptr) ? locker(msg) : nullptr; |
||||
} |
||||
MessageLock(const MessageLock&) = delete; |
||||
void operator=(const MessageLock&) = delete; |
||||
~MessageLock() { |
||||
if (unlocker_ != nullptr) { |
||||
unlocker_(msg_); |
||||
} |
||||
} |
||||
|
||||
private: |
||||
const upb_Message* msg_; |
||||
UpbExtensionUnlocker unlocker_; |
||||
}; |
||||
|
||||
bool HasExtensionOrUnknown(const upb_Message* msg, |
||||
const upb_MiniTableExtension* eid) { |
||||
MessageLock msg_lock(msg); |
||||
if (upb_Message_HasExtension(msg, eid)) return true; |
||||
|
||||
const int number = upb_MiniTableExtension_Number(eid); |
||||
return upb_Message_FindUnknown(msg, number, 0).status == kUpb_FindUnknown_Ok; |
||||
} |
||||
|
||||
bool GetOrPromoteExtension(upb_Message* msg, const upb_MiniTableExtension* eid, |
||||
upb_Arena* arena, upb_MessageValue* value) { |
||||
MessageLock msg_lock(msg); |
||||
upb_GetExtension_Status ext_status = upb_Message_GetOrPromoteExtension( |
||||
(upb_Message*)msg, eid, 0, arena, value); |
||||
return ext_status == kUpb_GetExtension_Ok; |
||||
} |
||||
|
||||
absl::StatusOr<absl::string_view> Serialize(const upb_Message* message, |
||||
const upb_MiniTable* mini_table, |
||||
upb_Arena* arena, int options) { |
||||
MessageLock msg_lock(message); |
||||
size_t len; |
||||
char* ptr; |
||||
upb_EncodeStatus status = |
||||
upb_Encode(message, mini_table, options, arena, &ptr, &len); |
||||
if (status == kUpb_EncodeStatus_Ok) { |
||||
return absl::string_view(ptr, len); |
||||
} |
||||
return MessageEncodeError(status); |
||||
} |
||||
|
||||
void DeepCopy(upb_Message* target, const upb_Message* source, |
||||
const upb_MiniTable* mini_table, upb_Arena* arena) { |
||||
MessageLock msg_lock(source); |
||||
upb_Message_DeepCopy(target, source, mini_table, arena); |
||||
} |
||||
|
||||
upb_Message* DeepClone(const upb_Message* source, |
||||
const upb_MiniTable* mini_table, upb_Arena* arena) { |
||||
MessageLock msg_lock(source); |
||||
return upb_Message_DeepClone(source, mini_table, arena); |
||||
} |
||||
|
||||
absl::Status MoveExtension(upb_Message* message, upb_Arena* message_arena, |
||||
const upb_MiniTableExtension* ext, |
||||
upb_Message* extension, upb_Arena* extension_arena) { |
||||
if (message_arena != extension_arena && |
||||
// Try fuse, if fusing is not allowed or fails, create copy of extension.
|
||||
!upb_Arena_Fuse(message_arena, extension_arena)) { |
||||
extension = DeepClone(extension, upb_MiniTableExtension_GetSubMessage(ext), |
||||
message_arena); |
||||
} |
||||
return upb_Message_SetExtension(message, ext, &extension, message_arena) |
||||
? absl::OkStatus() |
||||
: MessageAllocationError(); |
||||
} |
||||
|
||||
absl::Status SetExtension(upb_Message* message, upb_Arena* message_arena, |
||||
const upb_MiniTableExtension* ext, |
||||
const upb_Message* extension) { |
||||
// Clone extension into target message arena.
|
||||
extension = DeepClone(extension, upb_MiniTableExtension_GetSubMessage(ext), |
||||
message_arena); |
||||
return upb_Message_SetExtension(message, ext, &extension, message_arena) |
||||
? absl::OkStatus() |
||||
: MessageAllocationError(); |
||||
} |
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace protos
|
@ -0,0 +1,564 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google LLC. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#ifndef PROTOBUF_HPB_HPB_H_ |
||||
#define PROTOBUF_HPB_HPB_H_ |
||||
|
||||
#include <type_traits> |
||||
#include <vector> |
||||
|
||||
#include "absl/status/status.h" |
||||
#include "absl/status/statusor.h" |
||||
#include "upb/base/status.hpp" |
||||
#include "upb/mem/arena.hpp" |
||||
#include "upb/message/copy.h" |
||||
#include "upb/mini_table/extension.h" |
||||
#include "upb/wire/decode.h" |
||||
#include "upb/wire/encode.h" |
||||
|
||||
namespace protos { |
||||
|
||||
using Arena = ::upb::Arena; |
||||
class ExtensionRegistry; |
||||
|
||||
template <typename T> |
||||
using Proxy = std::conditional_t<std::is_const<T>::value, |
||||
typename std::remove_const_t<T>::CProxy, |
||||
typename T::Proxy>; |
||||
|
||||
// Provides convenient access to Proxy and CProxy message types.
|
||||
//
|
||||
// Using rebinding and handling of const, Ptr<Message> and Ptr<const Message>
|
||||
// allows copying const with T* const and avoids using non-copyable Proxy types
|
||||
// directly.
|
||||
template <typename T> |
||||
class Ptr final { |
||||
public: |
||||
Ptr() = delete; |
||||
|
||||
// Implicit conversions
|
||||
Ptr(T* m) : p_(m) {} // NOLINT
|
||||
Ptr(const Proxy<T>* p) : p_(*p) {} // NOLINT
|
||||
Ptr(Proxy<T> p) : p_(p) {} // NOLINT
|
||||
Ptr(const Ptr& m) = default; |
||||
|
||||
Ptr& operator=(Ptr v) & { |
||||
Proxy<T>::Rebind(p_, v.p_); |
||||
return *this; |
||||
} |
||||
|
||||
Proxy<T> operator*() const { return p_; } |
||||
Proxy<T>* operator->() const { |
||||
return const_cast<Proxy<T>*>(std::addressof(p_)); |
||||
} |
||||
|
||||
#ifdef __clang__ |
||||
#pragma clang diagnostic push |
||||
#pragma clang diagnostic ignored "-Wclass-conversion" |
||||
#endif |
||||
template <typename U = T, std::enable_if_t<!std::is_const<U>::value, int> = 0> |
||||
operator Ptr<const T>() const { |
||||
Proxy<const T> p(p_); |
||||
return Ptr<const T>(&p); |
||||
} |
||||
#ifdef __clang__ |
||||
#pragma clang diagnostic pop |
||||
#endif |
||||
|
||||
private: |
||||
Ptr(upb_Message* msg, upb_Arena* arena) : p_(msg, arena) {} // NOLINT
|
||||
|
||||
friend class Ptr<const T>; |
||||
friend typename T::Access; |
||||
|
||||
Proxy<T> p_; |
||||
}; |
||||
|
||||
inline absl::string_view UpbStrToStringView(upb_StringView str) { |
||||
return absl::string_view(str.data, str.size); |
||||
} |
||||
|
||||
// TODO: update bzl and move to upb runtime / protos.cc.
|
||||
inline upb_StringView UpbStrFromStringView(absl::string_view str, |
||||
upb_Arena* arena) { |
||||
const size_t str_size = str.size(); |
||||
char* buffer = static_cast<char*>(upb_Arena_Malloc(arena, str_size)); |
||||
memcpy(buffer, str.data(), str_size); |
||||
return upb_StringView_FromDataAndSize(buffer, str_size); |
||||
} |
||||
|
||||
template <typename T> |
||||
typename T::Proxy CreateMessage(::protos::Arena& arena) { |
||||
return typename T::Proxy(upb_Message_New(T::minitable(), arena.ptr()), |
||||
arena.ptr()); |
||||
} |
||||
|
||||
// begin:github_only
|
||||
// // This type exists to work around an absl type that has not yet been
|
||||
// // released.
|
||||
// struct SourceLocation {
|
||||
// static SourceLocation current() { return {}; }
|
||||
// absl::string_view file_name() { return "<unknown>"; }
|
||||
// int line() { return 0; }
|
||||
// };
|
||||
// end:github_only
|
||||
|
||||
// begin:google_only
|
||||
using SourceLocation = absl::SourceLocation; |
||||
// end:google_only
|
||||
|
||||
absl::Status MessageAllocationError( |
||||
SourceLocation loc = SourceLocation::current()); |
||||
|
||||
absl::Status ExtensionNotFoundError( |
||||
int extension_number, SourceLocation loc = SourceLocation::current()); |
||||
|
||||
absl::Status MessageDecodeError(upb_DecodeStatus status, |
||||
SourceLocation loc = SourceLocation::current()); |
||||
|
||||
absl::Status MessageEncodeError(upb_EncodeStatus status, |
||||
SourceLocation loc = SourceLocation::current()); |
||||
|
||||
namespace internal { |
||||
struct PrivateAccess { |
||||
template <typename T> |
||||
static auto* GetInternalMsg(T&& message) { |
||||
return message->msg(); |
||||
} |
||||
template <typename T> |
||||
static auto Proxy(upb_Message* p, upb_Arena* arena) { |
||||
return typename T::Proxy(p, arena); |
||||
} |
||||
template <typename T> |
||||
static auto CProxy(const upb_Message* p, upb_Arena* arena) { |
||||
return typename T::CProxy(p, arena); |
||||
} |
||||
template <typename T> |
||||
static auto CreateMessage(upb_Arena* arena) { |
||||
return typename T::Proxy(upb_Message_New(T::minitable(), arena), arena); |
||||
} |
||||
}; |
||||
|
||||
template <typename T> |
||||
auto* GetInternalMsg(T&& message) { |
||||
return PrivateAccess::GetInternalMsg(std::forward<T>(message)); |
||||
} |
||||
|
||||
template <typename T> |
||||
T CreateMessage() { |
||||
return T(); |
||||
} |
||||
|
||||
template <typename T> |
||||
typename T::Proxy CreateMessageProxy(upb_Message* msg, upb_Arena* arena) { |
||||
return typename T::Proxy(msg, arena); |
||||
} |
||||
|
||||
template <typename T> |
||||
typename T::CProxy CreateMessage(const upb_Message* msg, upb_Arena* arena) { |
||||
return PrivateAccess::CProxy<T>(msg, arena); |
||||
} |
||||
|
||||
class ExtensionMiniTableProvider { |
||||
public: |
||||
constexpr explicit ExtensionMiniTableProvider( |
||||
const upb_MiniTableExtension* mini_table_ext) |
||||
: mini_table_ext_(mini_table_ext) {} |
||||
const upb_MiniTableExtension* mini_table_ext() const { |
||||
return mini_table_ext_; |
||||
} |
||||
|
||||
private: |
||||
const upb_MiniTableExtension* mini_table_ext_; |
||||
}; |
||||
|
||||
// -------------------------------------------------------------------
|
||||
// ExtensionIdentifier
|
||||
// This is the type of actual extension objects. E.g. if you have:
|
||||
// extend Foo {
|
||||
// optional MyExtension bar = 1234;
|
||||
// }
|
||||
// then "bar" will be defined in C++ as:
|
||||
// ExtensionIdentifier<Foo, MyExtension> bar(&namespace_bar_ext);
|
||||
template <typename ExtendeeType, typename ExtensionType> |
||||
class ExtensionIdentifier : public ExtensionMiniTableProvider { |
||||
public: |
||||
using Extension = ExtensionType; |
||||
using Extendee = ExtendeeType; |
||||
|
||||
constexpr explicit ExtensionIdentifier( |
||||
const upb_MiniTableExtension* mini_table_ext) |
||||
: ExtensionMiniTableProvider(mini_table_ext) {} |
||||
}; |
||||
|
||||
template <typename T> |
||||
upb_Arena* GetArena(Ptr<T> message) { |
||||
return static_cast<upb_Arena*>(message->GetInternalArena()); |
||||
} |
||||
|
||||
template <typename T> |
||||
upb_Arena* GetArena(T* message) { |
||||
return static_cast<upb_Arena*>(message->GetInternalArena()); |
||||
} |
||||
|
||||
template <typename T> |
||||
const upb_MiniTable* GetMiniTable(const T*) { |
||||
return T::minitable(); |
||||
} |
||||
|
||||
template <typename T> |
||||
const upb_MiniTable* GetMiniTable(Ptr<T>) { |
||||
return T::minitable(); |
||||
} |
||||
|
||||
upb_ExtensionRegistry* GetUpbExtensions( |
||||
const ExtensionRegistry& extension_registry); |
||||
|
||||
absl::StatusOr<absl::string_view> Serialize(const upb_Message* message, |
||||
const upb_MiniTable* mini_table, |
||||
upb_Arena* arena, int options); |
||||
|
||||
bool HasExtensionOrUnknown(const upb_Message* msg, |
||||
const upb_MiniTableExtension* eid); |
||||
|
||||
bool GetOrPromoteExtension(upb_Message* msg, const upb_MiniTableExtension* eid, |
||||
upb_Arena* arena, upb_MessageValue* value); |
||||
|
||||
void DeepCopy(upb_Message* target, const upb_Message* source, |
||||
const upb_MiniTable* mini_table, upb_Arena* arena); |
||||
|
||||
upb_Message* DeepClone(const upb_Message* source, |
||||
const upb_MiniTable* mini_table, upb_Arena* arena); |
||||
|
||||
absl::Status MoveExtension(upb_Message* message, upb_Arena* message_arena, |
||||
const upb_MiniTableExtension* ext, |
||||
upb_Message* extension, upb_Arena* extension_arena); |
||||
|
||||
absl::Status SetExtension(upb_Message* message, upb_Arena* message_arena, |
||||
const upb_MiniTableExtension* ext, |
||||
const upb_Message* extension); |
||||
|
||||
template <typename T> |
||||
struct RemovePtr; |
||||
|
||||
template <typename T> |
||||
struct RemovePtr<Ptr<T>> { |
||||
using type = T; |
||||
}; |
||||
|
||||
template <typename T> |
||||
struct RemovePtr<T*> { |
||||
using type = T; |
||||
}; |
||||
|
||||
template <typename T> |
||||
using RemovePtrT = typename RemovePtr<T>::type; |
||||
|
||||
template <typename T, typename U = RemovePtrT<T>, |
||||
typename = std::enable_if_t<!std::is_const_v<U>>> |
||||
using PtrOrRaw = T; |
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T> |
||||
void DeepCopy(Ptr<const T> source_message, Ptr<T> target_message) { |
||||
static_assert(!std::is_const_v<T>); |
||||
::protos::internal::DeepCopy( |
||||
internal::GetInternalMsg(target_message), |
||||
internal::GetInternalMsg(source_message), T::minitable(), |
||||
static_cast<upb_Arena*>(target_message->GetInternalArena())); |
||||
} |
||||
|
||||
template <typename T> |
||||
typename T::Proxy CloneMessage(Ptr<T> message, upb_Arena* arena) { |
||||
return internal::PrivateAccess::Proxy<T>( |
||||
::protos::internal::DeepClone(internal::GetInternalMsg(message), |
||||
T::minitable(), arena), |
||||
arena); |
||||
} |
||||
|
||||
template <typename T> |
||||
void DeepCopy(Ptr<const T> source_message, T* target_message) { |
||||
static_assert(!std::is_const_v<T>); |
||||
DeepCopy(source_message, protos::Ptr(target_message)); |
||||
} |
||||
|
||||
template <typename T> |
||||
void DeepCopy(const T* source_message, Ptr<T> target_message) { |
||||
static_assert(!std::is_const_v<T>); |
||||
DeepCopy(protos::Ptr(source_message), target_message); |
||||
} |
||||
|
||||
template <typename T> |
||||
void DeepCopy(const T* source_message, T* target_message) { |
||||
static_assert(!std::is_const_v<T>); |
||||
DeepCopy(protos::Ptr(source_message), protos::Ptr(target_message)); |
||||
} |
||||
|
||||
template <typename T> |
||||
void ClearMessage(internal::PtrOrRaw<T> message) { |
||||
auto ptr = Ptr(message); |
||||
auto minitable = internal::GetMiniTable(ptr); |
||||
upb_Message_Clear(internal::GetInternalMsg(ptr), minitable); |
||||
} |
||||
|
||||
class ExtensionRegistry { |
||||
public: |
||||
ExtensionRegistry( |
||||
const std::vector<const ::protos::internal::ExtensionMiniTableProvider*>& |
||||
extensions, |
||||
const upb::Arena& arena) |
||||
: registry_(upb_ExtensionRegistry_New(arena.ptr())) { |
||||
if (registry_) { |
||||
for (const auto& ext_provider : extensions) { |
||||
const auto* ext = ext_provider->mini_table_ext(); |
||||
bool success = upb_ExtensionRegistry_AddArray(registry_, &ext, 1); |
||||
if (!success) { |
||||
registry_ = nullptr; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
private: |
||||
friend upb_ExtensionRegistry* ::protos::internal::GetUpbExtensions( |
||||
const ExtensionRegistry& extension_registry); |
||||
upb_ExtensionRegistry* registry_; |
||||
}; |
||||
|
||||
template <typename T> |
||||
using EnableIfProtosClass = std::enable_if_t< |
||||
std::is_base_of<typename T::Access, T>::value && |
||||
std::is_base_of<typename T::Access, typename T::ExtendableType>::value>; |
||||
|
||||
template <typename T> |
||||
using EnableIfMutableProto = std::enable_if_t<!std::is_const<T>::value>; |
||||
|
||||
template <typename T, typename Extendee, typename Extension, |
||||
typename = EnableIfProtosClass<T>> |
||||
ABSL_MUST_USE_RESULT bool HasExtension( |
||||
Ptr<T> message, |
||||
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) { |
||||
return ::protos::internal::HasExtensionOrUnknown( |
||||
::protos::internal::GetInternalMsg(message), id.mini_table_ext()); |
||||
} |
||||
|
||||
template <typename T, typename Extendee, typename Extension, |
||||
typename = EnableIfProtosClass<T>> |
||||
ABSL_MUST_USE_RESULT bool HasExtension( |
||||
const T* message, |
||||
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) { |
||||
return HasExtension(protos::Ptr(message), id); |
||||
} |
||||
|
||||
template <typename T, typename Extension, typename = EnableIfProtosClass<T>, |
||||
typename = EnableIfMutableProto<T>> |
||||
void ClearExtension( |
||||
Ptr<T> message, |
||||
const ::protos::internal::ExtensionIdentifier<T, Extension>& id) { |
||||
static_assert(!std::is_const_v<T>, ""); |
||||
upb_Message_ClearExtension(internal::GetInternalMsg(message), |
||||
id.mini_table_ext()); |
||||
} |
||||
|
||||
template <typename T, typename Extension, typename = EnableIfProtosClass<T>> |
||||
void ClearExtension( |
||||
T* message, |
||||
const ::protos::internal::ExtensionIdentifier<T, Extension>& id) { |
||||
ClearExtension(::protos::Ptr(message), id); |
||||
} |
||||
|
||||
template <typename T, typename Extension, typename = EnableIfProtosClass<T>, |
||||
typename = EnableIfMutableProto<T>> |
||||
absl::Status SetExtension( |
||||
Ptr<T> message, |
||||
const ::protos::internal::ExtensionIdentifier<T, Extension>& id, |
||||
const Extension& value) { |
||||
static_assert(!std::is_const_v<T>); |
||||
auto* message_arena = static_cast<upb_Arena*>(message->GetInternalArena()); |
||||
return ::protos::internal::SetExtension(internal::GetInternalMsg(message), |
||||
message_arena, id.mini_table_ext(), |
||||
internal::GetInternalMsg(&value)); |
||||
} |
||||
|
||||
template <typename T, typename Extension, typename = EnableIfProtosClass<T>, |
||||
typename = EnableIfMutableProto<T>> |
||||
absl::Status SetExtension( |
||||
Ptr<T> message, |
||||
const ::protos::internal::ExtensionIdentifier<T, Extension>& id, |
||||
Ptr<Extension> value) { |
||||
static_assert(!std::is_const_v<T>); |
||||
auto* message_arena = static_cast<upb_Arena*>(message->GetInternalArena()); |
||||
return ::protos::internal::SetExtension(internal::GetInternalMsg(message), |
||||
message_arena, id.mini_table_ext(), |
||||
internal::GetInternalMsg(value)); |
||||
} |
||||
|
||||
template <typename T, typename Extension, typename = EnableIfProtosClass<T>, |
||||
typename = EnableIfMutableProto<T>> |
||||
absl::Status SetExtension( |
||||
Ptr<T> message, |
||||
const ::protos::internal::ExtensionIdentifier<T, Extension>& id, |
||||
Extension&& value) { |
||||
Extension ext = std::move(value); |
||||
static_assert(!std::is_const_v<T>); |
||||
auto* message_arena = static_cast<upb_Arena*>(message->GetInternalArena()); |
||||
auto* extension_arena = static_cast<upb_Arena*>(ext.GetInternalArena()); |
||||
return ::protos::internal::MoveExtension( |
||||
internal::GetInternalMsg(message), message_arena, id.mini_table_ext(), |
||||
internal::GetInternalMsg(&ext), extension_arena); |
||||
} |
||||
|
||||
template <typename T, typename Extension, typename = EnableIfProtosClass<T>> |
||||
absl::Status SetExtension( |
||||
T* message, const ::protos::internal::ExtensionIdentifier<T, Extension>& id, |
||||
const Extension& value) { |
||||
return ::protos::SetExtension(::protos::Ptr(message), id, value); |
||||
} |
||||
|
||||
template <typename T, typename Extension, typename = EnableIfProtosClass<T>> |
||||
absl::Status SetExtension( |
||||
T* message, const ::protos::internal::ExtensionIdentifier<T, Extension>& id, |
||||
Extension&& value) { |
||||
return ::protos::SetExtension(::protos::Ptr(message), id, |
||||
std::forward<Extension>(value)); |
||||
} |
||||
|
||||
template <typename T, typename Extension, typename = EnableIfProtosClass<T>> |
||||
absl::Status SetExtension( |
||||
T* message, const ::protos::internal::ExtensionIdentifier<T, Extension>& id, |
||||
Ptr<Extension> value) { |
||||
return ::protos::SetExtension(::protos::Ptr(message), id, value); |
||||
} |
||||
|
||||
template <typename T, typename Extendee, typename Extension, |
||||
typename = EnableIfProtosClass<T>> |
||||
absl::StatusOr<Ptr<const Extension>> GetExtension( |
||||
Ptr<T> message, |
||||
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) { |
||||
// TODO: Fix const correctness issues.
|
||||
upb_MessageValue value; |
||||
const bool ok = ::protos::internal::GetOrPromoteExtension( |
||||
const_cast<upb_Message*>(internal::GetInternalMsg(message)), |
||||
id.mini_table_ext(), ::protos::internal::GetArena(message), &value); |
||||
if (!ok) { |
||||
return ExtensionNotFoundError( |
||||
upb_MiniTableExtension_Number(id.mini_table_ext())); |
||||
} |
||||
return Ptr<const Extension>(::protos::internal::CreateMessage<Extension>( |
||||
(upb_Message*)value.msg_val, ::protos::internal::GetArena(message))); |
||||
} |
||||
|
||||
template <typename T, typename Extendee, typename Extension, |
||||
typename = EnableIfProtosClass<T>> |
||||
absl::StatusOr<Ptr<const Extension>> GetExtension( |
||||
const T* message, |
||||
const ::protos::internal::ExtensionIdentifier<Extendee, Extension>& id) { |
||||
return GetExtension(protos::Ptr(message), id); |
||||
} |
||||
|
||||
template <typename T> |
||||
ABSL_MUST_USE_RESULT bool Parse(Ptr<T> message, absl::string_view bytes) { |
||||
static_assert(!std::is_const_v<T>); |
||||
upb_Message_Clear(internal::GetInternalMsg(message), |
||||
::protos::internal::GetMiniTable(message)); |
||||
auto* arena = static_cast<upb_Arena*>(message->GetInternalArena()); |
||||
return upb_Decode(bytes.data(), bytes.size(), |
||||
internal::GetInternalMsg(message), |
||||
::protos::internal::GetMiniTable(message), |
||||
/* extreg= */ nullptr, /* options= */ 0, |
||||
arena) == kUpb_DecodeStatus_Ok; |
||||
} |
||||
|
||||
template <typename T> |
||||
ABSL_MUST_USE_RESULT bool Parse( |
||||
Ptr<T> message, absl::string_view bytes, |
||||
const ::protos::ExtensionRegistry& extension_registry) { |
||||
static_assert(!std::is_const_v<T>); |
||||
upb_Message_Clear(internal::GetInternalMsg(message), |
||||
::protos::internal::GetMiniTable(message)); |
||||
auto* arena = static_cast<upb_Arena*>(message->GetInternalArena()); |
||||
return upb_Decode(bytes.data(), bytes.size(), |
||||
internal::GetInternalMsg(message), |
||||
::protos::internal::GetMiniTable(message), |
||||
/* extreg= */ |
||||
::protos::internal::GetUpbExtensions(extension_registry), |
||||
/* options= */ 0, arena) == kUpb_DecodeStatus_Ok; |
||||
} |
||||
|
||||
template <typename T> |
||||
ABSL_MUST_USE_RESULT bool Parse( |
||||
T* message, absl::string_view bytes, |
||||
const ::protos::ExtensionRegistry& extension_registry) { |
||||
static_assert(!std::is_const_v<T>); |
||||
return Parse(protos::Ptr(message, bytes, extension_registry)); |
||||
} |
||||
|
||||
template <typename T> |
||||
ABSL_MUST_USE_RESULT bool Parse(T* message, absl::string_view bytes) { |
||||
static_assert(!std::is_const_v<T>); |
||||
upb_Message_Clear(internal::GetInternalMsg(message), |
||||
::protos::internal::GetMiniTable(message)); |
||||
auto* arena = static_cast<upb_Arena*>(message->GetInternalArena()); |
||||
return upb_Decode(bytes.data(), bytes.size(), |
||||
internal::GetInternalMsg(message), |
||||
::protos::internal::GetMiniTable(message), |
||||
/* extreg= */ nullptr, /* options= */ 0, |
||||
arena) == kUpb_DecodeStatus_Ok; |
||||
} |
||||
|
||||
template <typename T> |
||||
absl::StatusOr<T> Parse(absl::string_view bytes, int options = 0) { |
||||
T message; |
||||
auto* arena = static_cast<upb_Arena*>(message.GetInternalArena()); |
||||
upb_DecodeStatus status = |
||||
upb_Decode(bytes.data(), bytes.size(), message.msg(), |
||||
::protos::internal::GetMiniTable(&message), |
||||
/* extreg= */ nullptr, /* options= */ 0, arena); |
||||
if (status == kUpb_DecodeStatus_Ok) { |
||||
return message; |
||||
} |
||||
return MessageDecodeError(status); |
||||
} |
||||
|
||||
template <typename T> |
||||
absl::StatusOr<T> Parse(absl::string_view bytes, |
||||
const ::protos::ExtensionRegistry& extension_registry, |
||||
int options = 0) { |
||||
T message; |
||||
auto* arena = static_cast<upb_Arena*>(message.GetInternalArena()); |
||||
upb_DecodeStatus status = |
||||
upb_Decode(bytes.data(), bytes.size(), message.msg(), |
||||
::protos::internal::GetMiniTable(&message), |
||||
::protos::internal::GetUpbExtensions(extension_registry), |
||||
/* options= */ 0, arena); |
||||
if (status == kUpb_DecodeStatus_Ok) { |
||||
return message; |
||||
} |
||||
return MessageDecodeError(status); |
||||
} |
||||
|
||||
template <typename T> |
||||
absl::StatusOr<absl::string_view> Serialize(const T* message, upb::Arena& arena, |
||||
int options = 0) { |
||||
return ::protos::internal::Serialize( |
||||
internal::GetInternalMsg(message), |
||||
::protos::internal::GetMiniTable(message), arena.ptr(), options); |
||||
} |
||||
|
||||
template <typename T> |
||||
absl::StatusOr<absl::string_view> Serialize(Ptr<T> message, upb::Arena& arena, |
||||
int options = 0) { |
||||
return ::protos::internal::Serialize( |
||||
internal::GetInternalMsg(message), |
||||
::protos::internal::GetMiniTable(message), arena.ptr(), options); |
||||
} |
||||
|
||||
} // namespace protos
|
||||
|
||||
#endif // PROTOBUF_HPB_HPB_H_
|
@ -0,0 +1,31 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google LLC. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#ifndef PROTOBUF_HPB_EXTENSION_LOCK_H_ |
||||
#define PROTOBUF_HPB_EXTENSION_LOCK_H_ |
||||
|
||||
#include <atomic> |
||||
|
||||
namespace protos::internal { |
||||
|
||||
// TODO: Temporary locking api for cross-language
|
||||
// concurrency issue around extension api that uses lazy promotion
|
||||
// from unknown data to upb_MiniTableExtension. Will be replaced by
|
||||
// a core runtime solution in the future.
|
||||
//
|
||||
// Any api(s) using unknown or extension data (GetOrPromoteExtension,
|
||||
// Serialize and others) call lock/unlock to provide a way for
|
||||
// mixed language implementations to avoid race conditions)
|
||||
using UpbExtensionUnlocker = void (*)(const void*); |
||||
using UpbExtensionLocker = UpbExtensionUnlocker (*)(const void*); |
||||
|
||||
// TODO: Expose as function instead of global.
|
||||
extern std::atomic<UpbExtensionLocker> upb_extension_locker_global; |
||||
|
||||
} // namespace protos::internal
|
||||
|
||||
#endif // PROTOBUF_HPB_EXTENSION_LOCK_H_
|
@ -0,0 +1,25 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google LLC. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#ifndef PROTOBUF_HPB_INTERNAL_H_ |
||||
#define PROTOBUF_HPB_INTERNAL_H_ |
||||
|
||||
#include "upb/mem/arena.h" |
||||
#include "upb/message/message.h" |
||||
|
||||
namespace protos::internal { |
||||
|
||||
// Moves ownership of a message created in a source arena.
|
||||
//
|
||||
// Utility function to provide a way to move ownership across languages or VMs.
|
||||
template <typename T> |
||||
T MoveMessage(upb_Message* msg, upb_Arena* arena) { |
||||
return T(msg, arena); |
||||
} |
||||
|
||||
} // namespace protos::internal
|
||||
#endif |
@ -0,0 +1,21 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google LLC. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#ifndef PROTOBUF_HPB_TRAITS_H_ |
||||
#define PROTOBUF_HPB_TRAITS_H_ |
||||
|
||||
#include <type_traits> |
||||
|
||||
namespace protos::internal { |
||||
|
||||
template <typename T, typename T2> |
||||
using add_const_if_T_is_const = |
||||
std::conditional_t<std::is_const_v<T>, const T2, T2>; |
||||
|
||||
} // namespace protos::internal
|
||||
|
||||
#endif // PROTOBUF_HPB_TRAITS_H_
|
@ -0,0 +1,300 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google LLC. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#ifndef PROTOBUF_HPB_REPEATED_FIELD_H_ |
||||
#define PROTOBUF_HPB_REPEATED_FIELD_H_ |
||||
|
||||
#include <assert.h> |
||||
|
||||
#include <cstddef> |
||||
#include <iterator> |
||||
#include <type_traits> |
||||
|
||||
#include "absl/strings/string_view.h" |
||||
#include "google/protobuf/hpb/protos.h" |
||||
#include "google/protobuf/hpb/protos_traits.h" |
||||
#include "google/protobuf/hpb/repeated_field_iterator.h" |
||||
#include "upb/base/string_view.h" |
||||
#include "upb/mem/arena.h" |
||||
#include "upb/message/array.h" |
||||
#include "upb/message/copy.h" |
||||
#include "upb/message/message.h" |
||||
|
||||
namespace protos { |
||||
namespace internal { |
||||
|
||||
// Shared implementation of repeated fields for absl::string_view and
|
||||
// message types for mutable and immutable variants.
|
||||
//
|
||||
// Immutable (const accessor), constructs this class with a nullptr upb_Array*
|
||||
// when the underlying array in the message is empty.
|
||||
//
|
||||
// Mutable accessors on the other hand, will allocate a new empty non-null
|
||||
// upb_Array* for the message when the RepeatedFieldProxy is constructed.
|
||||
template <class T> |
||||
class RepeatedFieldProxyBase { |
||||
using Array = add_const_if_T_is_const<T, upb_Array>; |
||||
|
||||
public: |
||||
explicit RepeatedFieldProxyBase(Array* arr, upb_Arena* arena) |
||||
: arr_(arr), arena_(arena) {} |
||||
|
||||
size_t size() const { return arr_ != nullptr ? upb_Array_Size(arr_) : 0; } |
||||
|
||||
bool empty() const { return size() == 0; } |
||||
|
||||
protected: |
||||
// Returns upb_Array message member.
|
||||
inline upb_Message* GetMessage(size_t n) const; |
||||
|
||||
Array* arr_; |
||||
upb_Arena* arena_; |
||||
}; |
||||
|
||||
template <class T> |
||||
upb_Message* RepeatedFieldProxyBase<T>::GetMessage(size_t n) const { |
||||
auto** messages = |
||||
static_cast<upb_Message**>(upb_Array_MutableDataPtr(this->arr_)); |
||||
return messages[n]; |
||||
} |
||||
|
||||
template <class T> |
||||
class RepeatedFieldProxyMutableBase : public RepeatedFieldProxyBase<T> { |
||||
public: |
||||
RepeatedFieldProxyMutableBase(upb_Array* arr, upb_Arena* arena) |
||||
: RepeatedFieldProxyBase<T>(arr, arena) {} |
||||
|
||||
void clear() { upb_Array_Resize(this->arr_, 0, this->arena_); } |
||||
}; |
||||
|
||||
// RepeatedField proxy for repeated messages.
|
||||
template <class T> |
||||
class RepeatedFieldProxy |
||||
: public std::conditional_t<std::is_const_v<T>, RepeatedFieldProxyBase<T>, |
||||
RepeatedFieldProxyMutableBase<T>> { |
||||
static_assert(!std::is_same_v<T, absl::string_view>, ""); |
||||
static_assert(!std::is_same_v<T, const absl::string_view>, ""); |
||||
static_assert(!std::is_arithmetic_v<T>, ""); |
||||
static constexpr bool kIsConst = std::is_const_v<T>; |
||||
|
||||
public: |
||||
using value_type = std::remove_const_t<T>; |
||||
using size_type = size_t; |
||||
using difference_type = ptrdiff_t; |
||||
using iterator = internal::Iterator<MessageIteratorPolicy<T>>; |
||||
using reference = typename iterator::reference; |
||||
using pointer = typename iterator::pointer; |
||||
using reverse_iterator = std::reverse_iterator<iterator>; |
||||
|
||||
explicit RepeatedFieldProxy(const upb_Array* arr, upb_Arena* arena) |
||||
: RepeatedFieldProxyBase<T>(arr, arena) {} |
||||
RepeatedFieldProxy(upb_Array* arr, upb_Arena* arena) |
||||
: RepeatedFieldProxyMutableBase<T>(arr, arena) {} |
||||
// Constructor used by ::protos::Ptr.
|
||||
RepeatedFieldProxy(const RepeatedFieldProxy&) = default; |
||||
|
||||
// T::CProxy [] operator specialization.
|
||||
typename T::CProxy operator[](size_t n) const { |
||||
upb_MessageValue message_value = upb_Array_Get(this->arr_, n); |
||||
return ::protos::internal::CreateMessage<typename std::remove_const_t<T>>( |
||||
(upb_Message*)message_value.msg_val, this->arena_); |
||||
} |
||||
|
||||
// TODO : Audit/Finalize based on Iterator Design.
|
||||
// T::Proxy [] operator specialization.
|
||||
template <int&... DeductionBlocker, bool b = !kIsConst, |
||||
typename = std::enable_if_t<b>> |
||||
typename T::Proxy operator[](size_t n) { |
||||
return ::protos::internal::CreateMessageProxy<T>(this->GetMessage(n), |
||||
this->arena_); |
||||
} |
||||
|
||||
// Mutable message reference specialization.
|
||||
template <int&... DeductionBlocker, bool b = !kIsConst, |
||||
typename = std::enable_if_t<b>> |
||||
void push_back(const T& t) { |
||||
upb_MessageValue message_value; |
||||
message_value.msg_val = upb_Message_DeepClone( |
||||
PrivateAccess::GetInternalMsg(&t), ::protos::internal::GetMiniTable(&t), |
||||
this->arena_); |
||||
upb_Array_Append(this->arr_, message_value, this->arena_); |
||||
} |
||||
|
||||
// Mutable message add using move.
|
||||
template <int&... DeductionBlocker, bool b = !kIsConst, |
||||
typename = std::enable_if_t<b>> |
||||
void push_back(T&& msg) { |
||||
upb_MessageValue message_value; |
||||
message_value.msg_val = PrivateAccess::GetInternalMsg(&msg); |
||||
upb_Arena_Fuse(GetArena(&msg), this->arena_); |
||||
upb_Array_Append(this->arr_, message_value, this->arena_); |
||||
T moved_msg = std::move(msg); |
||||
} |
||||
|
||||
iterator begin() const { |
||||
return iterator( |
||||
{static_cast<upb_Message**>( |
||||
this->arr_ ? const_cast<void*>(upb_Array_DataPtr(this->arr_)) |
||||
: nullptr), |
||||
this->arena_}); |
||||
} |
||||
iterator end() const { return begin() + this->size(); } |
||||
reverse_iterator rbegin() const { return reverse_iterator(end()); } |
||||
reverse_iterator rend() const { return reverse_iterator(begin()); } |
||||
|
||||
private: |
||||
friend class ::protos::Ptr<T>; |
||||
}; |
||||
|
||||
// RepeatedField proxy for repeated strings.
|
||||
template <class T> |
||||
class RepeatedFieldStringProxy |
||||
: public std::conditional_t<std::is_const_v<T>, RepeatedFieldProxyBase<T>, |
||||
RepeatedFieldProxyMutableBase<T>> { |
||||
static_assert(std::is_same_v<T, absl::string_view> || |
||||
std::is_same_v<T, const absl::string_view>, |
||||
""); |
||||
static constexpr bool kIsConst = std::is_const_v<T>; |
||||
|
||||
public: |
||||
using value_type = std::remove_const_t<T>; |
||||
using size_type = size_t; |
||||
using difference_type = ptrdiff_t; |
||||
using iterator = internal::Iterator<StringIteratorPolicy<T>>; |
||||
using reference = typename iterator::reference; |
||||
using pointer = typename iterator::pointer; |
||||
using reverse_iterator = std::reverse_iterator<iterator>; |
||||
|
||||
// Immutable constructor.
|
||||
explicit RepeatedFieldStringProxy(const upb_Array* arr, upb_Arena* arena) |
||||
: RepeatedFieldProxyBase<T>(arr, arena) {} |
||||
// Mutable constructor.
|
||||
RepeatedFieldStringProxy(upb_Array* arr, upb_Arena* arena) |
||||
: RepeatedFieldProxyMutableBase<T>(arr, arena) {} |
||||
// Constructor used by ::protos::Ptr.
|
||||
RepeatedFieldStringProxy(const RepeatedFieldStringProxy&) = default; |
||||
|
||||
reference operator[](size_t n) const { return begin()[n]; } |
||||
|
||||
template <int&... DeductionBlocker, bool b = !kIsConst, |
||||
typename = std::enable_if_t<b>> |
||||
void push_back(T t) { |
||||
upb_MessageValue message_value; |
||||
// Copy string to arena.
|
||||
assert(this->arena_); |
||||
char* data = (char*)upb_Arena_Malloc(this->arena_, t.size()); |
||||
assert(data); |
||||
memcpy(data, t.data(), t.size()); |
||||
message_value.str_val = upb_StringView_FromDataAndSize(data, t.size()); |
||||
upb_Array_Append(this->arr_, message_value, this->arena_); |
||||
} |
||||
|
||||
iterator begin() const { return iterator({this->arr_, this->arena_, 0}); } |
||||
iterator end() const { |
||||
return iterator({this->arr_, this->arena_, this->size()}); |
||||
} |
||||
reverse_iterator rbegin() const { return reverse_iterator(end()); } |
||||
reverse_iterator rend() const { return reverse_iterator(begin()); } |
||||
}; |
||||
|
||||
// RepeatedField proxy for repeated scalar types.
|
||||
template <typename T> |
||||
class RepeatedFieldScalarProxy |
||||
: public std::conditional_t<std::is_const_v<T>, RepeatedFieldProxyBase<T>, |
||||
RepeatedFieldProxyMutableBase<T>> { |
||||
static_assert(std::is_arithmetic_v<T>, ""); |
||||
static constexpr bool kIsConst = std::is_const_v<T>; |
||||
|
||||
public: |
||||
using value_type = std::remove_const_t<T>; |
||||
using size_type = size_t; |
||||
using difference_type = ptrdiff_t; |
||||
using iterator = internal::Iterator<ScalarIteratorPolicy<T>>; |
||||
using reference = typename iterator::reference; |
||||
using pointer = typename iterator::pointer; |
||||
using reverse_iterator = std::reverse_iterator<iterator>; |
||||
|
||||
explicit RepeatedFieldScalarProxy(const upb_Array* arr, upb_Arena* arena) |
||||
: RepeatedFieldProxyBase<T>(arr, arena) {} |
||||
RepeatedFieldScalarProxy(upb_Array* arr, upb_Arena* arena) |
||||
: RepeatedFieldProxyMutableBase<T>(arr, arena) {} |
||||
// Constructor used by ::protos::Ptr.
|
||||
RepeatedFieldScalarProxy(const RepeatedFieldScalarProxy&) = default; |
||||
|
||||
T operator[](size_t n) const { |
||||
upb_MessageValue message_value = upb_Array_Get(this->arr_, n); |
||||
typename std::remove_const_t<T> val; |
||||
memcpy(&val, &message_value, sizeof(T)); |
||||
return val; |
||||
} |
||||
|
||||
template <int&... DeductionBlocker, bool b = !kIsConst, |
||||
typename = std::enable_if_t<b>> |
||||
void push_back(T t) { |
||||
upb_MessageValue message_value; |
||||
memcpy(&message_value, &t, sizeof(T)); |
||||
upb_Array_Append(this->arr_, message_value, this->arena_); |
||||
} |
||||
|
||||
iterator begin() const { return iterator({unsafe_array()}); } |
||||
iterator cbegin() const { return begin(); } |
||||
iterator end() const { return iterator({unsafe_array() + this->size()}); } |
||||
iterator cend() const { return end(); } |
||||
|
||||
// Reverse iterator support.
|
||||
reverse_iterator rbegin() const { return reverse_iterator(end()); } |
||||
reverse_iterator rend() const { return reverse_iterator(begin()); } |
||||
reverse_iterator crbegin() const { return reverse_iterator(end()); } |
||||
reverse_iterator crend() const { return reverse_iterator(begin()); } |
||||
|
||||
private: |
||||
T* unsafe_array() const { |
||||
if (kIsConst) { |
||||
const void* unsafe_ptr = ::upb_Array_DataPtr(this->arr_); |
||||
return static_cast<T*>(const_cast<void*>(unsafe_ptr)); |
||||
} |
||||
if (!kIsConst) { |
||||
void* unsafe_ptr = |
||||
::upb_Array_MutableDataPtr(const_cast<upb_Array*>(this->arr_)); |
||||
return static_cast<T*>(unsafe_ptr); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T> |
||||
class RepeatedField { |
||||
static constexpr bool kIsString = std::is_same_v<T, absl::string_view>; |
||||
static constexpr bool kIsScalar = std::is_arithmetic_v<T>; |
||||
|
||||
public: |
||||
using Proxy = std::conditional_t< |
||||
kIsScalar, internal::RepeatedFieldScalarProxy<T>, |
||||
std::conditional_t<kIsString, internal::RepeatedFieldStringProxy<T>, |
||||
internal::RepeatedFieldProxy<T>>>; |
||||
using CProxy = std::conditional_t< |
||||
kIsScalar, internal::RepeatedFieldScalarProxy<const T>, |
||||
std::conditional_t<kIsString, internal::RepeatedFieldStringProxy<const T>, |
||||
internal::RepeatedFieldProxy<const T>>>; |
||||
// TODO: T supports incomplete type from fwd.h forwarding headers
|
||||
// We would like to reference T::CProxy. Validate forwarding header design.
|
||||
using ValueProxy = std::conditional_t< |
||||
kIsScalar, T, |
||||
std::conditional_t<kIsString, absl::string_view, ::protos::Ptr<T>>>; |
||||
using ValueCProxy = std::conditional_t< |
||||
kIsScalar, const T, |
||||
std::conditional_t<kIsString, absl::string_view, ::protos::Ptr<const T>>>; |
||||
using Access = std::conditional_t< |
||||
kIsScalar, internal::RepeatedFieldScalarProxy<T>, |
||||
std::conditional_t<kIsString, internal::RepeatedFieldStringProxy<T>, |
||||
internal::RepeatedFieldProxy<T>>>; |
||||
}; |
||||
|
||||
} // namespace protos
|
||||
|
||||
#endif // PROTOBUF_HPB_REPEATED_FIELD_H_
|
@ -0,0 +1,370 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google LLC. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#ifndef PROTOBUF_HPB_REPEATED_FIELD_ITERATOR_H_ |
||||
#define PROTOBUF_HPB_REPEATED_FIELD_ITERATOR_H_ |
||||
|
||||
#include <cstddef> |
||||
#include <cstring> |
||||
#include <iterator> |
||||
#include <type_traits> |
||||
|
||||
#include "absl/strings/string_view.h" |
||||
#include "google/protobuf/hpb/protos.h" |
||||
#include "upb/base/string_view.h" |
||||
#include "upb/mem/arena.h" |
||||
#include "upb/message/array.h" |
||||
#include "upb/message/message.h" |
||||
|
||||
namespace protos { |
||||
namespace internal { |
||||
|
||||
// TODO: Implement std iterator for messages
|
||||
template <typename T> |
||||
class RepeatedFieldScalarProxy; |
||||
template <typename T> |
||||
class RepeatedFieldStringProxy; |
||||
|
||||
struct IteratorTestPeer; |
||||
|
||||
template <typename T> |
||||
class Iterator; |
||||
|
||||
template <typename PolicyT> |
||||
class ReferenceProxy; |
||||
|
||||
template <typename PolicyT> |
||||
class InjectedRelationalsImpl { |
||||
using RP = ReferenceProxy<PolicyT>; |
||||
using V = typename PolicyT::value_type; |
||||
friend bool operator==(RP a, V b) { return static_cast<V>(a) == b; } |
||||
friend bool operator==(V a, RP b) { return a == static_cast<V>(b); } |
||||
friend bool operator==(RP a, RP b) { |
||||
return static_cast<V>(a) == static_cast<V>(b); |
||||
} |
||||
friend bool operator!=(RP a, V b) { return static_cast<V>(a) != b; } |
||||
friend bool operator!=(V a, RP b) { return a != static_cast<V>(b); } |
||||
friend bool operator!=(RP a, RP b) { |
||||
return static_cast<V>(a) != static_cast<V>(b); |
||||
} |
||||
friend bool operator<(RP a, V b) { return static_cast<V>(a) < b; } |
||||
friend bool operator<(V a, RP b) { return a < static_cast<V>(b); } |
||||
friend bool operator<(RP a, RP b) { |
||||
return static_cast<V>(a) < static_cast<V>(b); |
||||
} |
||||
friend bool operator<=(RP a, V b) { return static_cast<V>(a) <= b; } |
||||
friend bool operator<=(V a, RP b) { return a <= static_cast<V>(b); } |
||||
friend bool operator<=(RP a, RP b) { |
||||
return static_cast<V>(a) <= static_cast<V>(b); |
||||
} |
||||
friend bool operator>(RP a, V b) { return static_cast<V>(a) > b; } |
||||
friend bool operator>(V a, RP b) { return a > static_cast<V>(b); } |
||||
friend bool operator>(RP a, RP b) { |
||||
return static_cast<V>(a) > static_cast<V>(b); |
||||
} |
||||
friend bool operator>=(RP a, V b) { return static_cast<V>(a) >= b; } |
||||
friend bool operator>=(V a, RP b) { return a >= static_cast<V>(b); } |
||||
friend bool operator>=(RP a, RP b) { |
||||
return static_cast<V>(a) >= static_cast<V>(b); |
||||
} |
||||
}; |
||||
class NoInjectedRelationalsImpl {}; |
||||
|
||||
// We need to inject relationals for the string references because the
|
||||
// relationals for string_view are templates and won't allow for implicit
|
||||
// conversions from ReferenceProxy to string_view before deduction.
|
||||
template <typename PolicyT> |
||||
using InjectedRelationals = std::conditional_t< |
||||
std::is_same_v<std::remove_const_t<typename PolicyT::value_type>, |
||||
absl::string_view>, |
||||
InjectedRelationalsImpl<PolicyT>, NoInjectedRelationalsImpl>; |
||||
|
||||
template <typename PolicyT> |
||||
class ReferenceProxy : InjectedRelationals<PolicyT> { |
||||
using value_type = typename PolicyT::value_type; |
||||
|
||||
public: |
||||
ReferenceProxy(const ReferenceProxy&) = default; |
||||
ReferenceProxy& operator=(const ReferenceProxy& other) { |
||||
// Assign through the references
|
||||
// TODO: Make this better for strings to avoid the copy.
|
||||
it_.Set(other.it_.Get()); |
||||
return *this; |
||||
} |
||||
friend void swap(ReferenceProxy a, ReferenceProxy b) { a.it_.swap(b.it_); } |
||||
|
||||
operator value_type() const { return it_.Get(); } |
||||
void operator=(const value_type& value) const { it_.Set(value); } |
||||
void operator=(value_type&& value) const { it_.Set(std::move(value)); } |
||||
Iterator<PolicyT> operator&() const { return Iterator<PolicyT>(it_); } |
||||
|
||||
private: |
||||
friend IteratorTestPeer; |
||||
friend ReferenceProxy<typename PolicyT::AddConst>; |
||||
friend Iterator<PolicyT>; |
||||
|
||||
explicit ReferenceProxy(typename PolicyT::Payload elem) : it_(elem) {} |
||||
typename PolicyT::Payload it_; |
||||
}; |
||||
|
||||
template <template <typename> class PolicyTemplate, typename T> |
||||
class ReferenceProxy<PolicyTemplate<const T>> |
||||
: InjectedRelationals<PolicyTemplate<const T>> { |
||||
using PolicyT = PolicyTemplate<const T>; |
||||
using value_type = typename PolicyT::value_type; |
||||
|
||||
public: |
||||
ReferenceProxy(ReferenceProxy<PolicyTemplate<T>> p) : it_(p.it_) {} |
||||
ReferenceProxy(const ReferenceProxy&) = default; |
||||
ReferenceProxy& operator=(const ReferenceProxy&) = delete; |
||||
|
||||
operator value_type() const { return it_.Get(); } |
||||
Iterator<PolicyT> operator&() const { return Iterator<PolicyT>(it_); } |
||||
|
||||
private: |
||||
friend IteratorTestPeer; |
||||
friend Iterator<PolicyT>; |
||||
|
||||
explicit ReferenceProxy(typename PolicyT::Payload elem) : it_(elem) {} |
||||
typename PolicyT::Payload it_; |
||||
}; |
||||
|
||||
template <typename PolicyT> |
||||
class Iterator { |
||||
public: |
||||
using iterator_category = std::random_access_iterator_tag; |
||||
using value_type = std::remove_const_t<typename PolicyT::value_type>; |
||||
using difference_type = std::ptrdiff_t; |
||||
using pointer = Iterator; |
||||
using reference = |
||||
std::conditional_t<PolicyT::kUseReferenceProxy, ReferenceProxy<PolicyT>, |
||||
typename PolicyT::value_type>; |
||||
|
||||
constexpr Iterator() noexcept : it_(nullptr) {} |
||||
Iterator(const Iterator& other) = default; |
||||
Iterator& operator=(const Iterator& other) = default; |
||||
template < |
||||
typename P = PolicyT, |
||||
typename = std::enable_if_t<std::is_const<typename P::value_type>::value>> |
||||
Iterator(const Iterator<typename P::RemoveConst>& other) : it_(other.it_) {} |
||||
|
||||
constexpr reference operator*() const noexcept { |
||||
if constexpr (PolicyT::kUseReferenceProxy) { |
||||
return reference(it_); |
||||
} else { |
||||
return it_.Get(); |
||||
} |
||||
} |
||||
// No operator-> needed because T is a scalar.
|
||||
|
||||
private: |
||||
// Hide the internal type.
|
||||
using iterator = Iterator; |
||||
|
||||
public: |
||||
// {inc,dec}rementable
|
||||
constexpr iterator& operator++() noexcept { |
||||
it_.AddOffset(1); |
||||
return *this; |
||||
} |
||||
constexpr iterator operator++(int) noexcept { |
||||
auto copy = *this; |
||||
++*this; |
||||
return copy; |
||||
} |
||||
constexpr iterator& operator--() noexcept { |
||||
it_.AddOffset(-1); |
||||
return *this; |
||||
} |
||||
constexpr iterator operator--(int) noexcept { |
||||
auto copy = *this; |
||||
--*this; |
||||
return copy; |
||||
} |
||||
|
||||
// equality_comparable
|
||||
friend constexpr bool operator==(const iterator& x, |
||||
const iterator& y) noexcept { |
||||
return x.it_.Index() == y.it_.Index(); |
||||
} |
||||
friend constexpr bool operator!=(const iterator& x, |
||||
const iterator& y) noexcept { |
||||
return !(x == y); |
||||
} |
||||
|
||||
// less_than_comparable
|
||||
friend constexpr bool operator<(const iterator& x, |
||||
const iterator& y) noexcept { |
||||
return x.it_.Index() < y.it_.Index(); |
||||
} |
||||
friend constexpr bool operator<=(const iterator& x, |
||||
const iterator& y) noexcept { |
||||
return !(y < x); |
||||
} |
||||
friend constexpr bool operator>(const iterator& x, |
||||
const iterator& y) noexcept { |
||||
return y < x; |
||||
} |
||||
friend constexpr bool operator>=(const iterator& x, |
||||
const iterator& y) noexcept { |
||||
return !(x < y); |
||||
} |
||||
|
||||
constexpr iterator& operator+=(difference_type d) noexcept { |
||||
it_.AddOffset(d); |
||||
return *this; |
||||
} |
||||
constexpr iterator operator+(difference_type d) const noexcept { |
||||
auto copy = *this; |
||||
copy += d; |
||||
return copy; |
||||
} |
||||
friend constexpr iterator operator+(const difference_type d, |
||||
iterator it) noexcept { |
||||
return it + d; |
||||
} |
||||
|
||||
constexpr iterator& operator-=(difference_type d) noexcept { |
||||
it_.AddOffset(-d); |
||||
return *this; |
||||
} |
||||
constexpr iterator operator-(difference_type d) const noexcept { |
||||
auto copy = *this; |
||||
copy -= d; |
||||
return copy; |
||||
} |
||||
|
||||
// indexable
|
||||
constexpr reference operator[](difference_type d) const noexcept { |
||||
auto copy = *this; |
||||
copy += d; |
||||
return *copy; |
||||
} |
||||
|
||||
// random access iterator
|
||||
friend constexpr difference_type operator-(iterator x, iterator y) noexcept { |
||||
return x.it_.Index() - y.it_.Index(); |
||||
} |
||||
|
||||
private: |
||||
friend IteratorTestPeer; |
||||
friend ReferenceProxy<PolicyT>; |
||||
friend Iterator<typename PolicyT::AddConst>; |
||||
template <typename U> |
||||
friend class RepeatedFieldScalarProxy; |
||||
template <typename U> |
||||
friend class RepeatedFieldStringProxy; |
||||
template <typename U> |
||||
friend class RepeatedFieldProxy; |
||||
|
||||
// Create from internal::RepeatedFieldScalarProxy.
|
||||
explicit Iterator(typename PolicyT::Payload it) noexcept : it_(it) {} |
||||
|
||||
// The internal iterator.
|
||||
typename PolicyT::Payload it_; |
||||
}; |
||||
|
||||
template <typename T> |
||||
struct ScalarIteratorPolicy { |
||||
static constexpr bool kUseReferenceProxy = true; |
||||
using value_type = T; |
||||
using RemoveConst = ScalarIteratorPolicy<std::remove_const_t<T>>; |
||||
using AddConst = ScalarIteratorPolicy<const T>; |
||||
|
||||
struct Payload { |
||||
T* value; |
||||
void AddOffset(ptrdiff_t offset) { value += offset; } |
||||
T Get() const { return *value; } |
||||
void Set(T new_value) const { *value = new_value; } |
||||
T* Index() const { return value; } |
||||
|
||||
void swap(Payload& other) { |
||||
using std::swap; |
||||
swap(*value, *other.value); |
||||
} |
||||
|
||||
operator typename ScalarIteratorPolicy<const T>::Payload() const { |
||||
return {value}; |
||||
} |
||||
}; |
||||
}; |
||||
|
||||
template <typename T> |
||||
struct StringIteratorPolicy { |
||||
static constexpr bool kUseReferenceProxy = true; |
||||
using value_type = T; |
||||
using RemoveConst = StringIteratorPolicy<std::remove_const_t<T>>; |
||||
using AddConst = StringIteratorPolicy<const T>; |
||||
|
||||
struct Payload { |
||||
using Array = |
||||
std::conditional_t<std::is_const_v<T>, const upb_Array, upb_Array>; |
||||
Array* arr; |
||||
upb_Arena* arena; |
||||
size_t index; |
||||
|
||||
void AddOffset(ptrdiff_t offset) { index += offset; } |
||||
absl::string_view Get() const { |
||||
upb_MessageValue message_value = upb_Array_Get(arr, index); |
||||
return absl::string_view(message_value.str_val.data, |
||||
message_value.str_val.size); |
||||
} |
||||
void Set(absl::string_view new_value) const { |
||||
char* data = |
||||
static_cast<char*>(upb_Arena_Malloc(arena, new_value.size())); |
||||
memcpy(data, new_value.data(), new_value.size()); |
||||
upb_MessageValue message_value; |
||||
message_value.str_val = |
||||
upb_StringView_FromDataAndSize(data, new_value.size()); |
||||
upb_Array_Set(arr, index, message_value); |
||||
} |
||||
size_t Index() const { return index; } |
||||
|
||||
void swap(Payload& other) { |
||||
upb_MessageValue a = upb_Array_Get(this->arr, this->index); |
||||
upb_MessageValue b = upb_Array_Get(other.arr, other.index); |
||||
upb_Array_Set(this->arr, this->index, b); |
||||
upb_Array_Set(other.arr, other.index, a); |
||||
} |
||||
|
||||
operator typename StringIteratorPolicy<const T>::Payload() const { |
||||
return {arr, arena, index}; |
||||
} |
||||
}; |
||||
}; |
||||
|
||||
template <typename T> |
||||
struct MessageIteratorPolicy { |
||||
static constexpr bool kUseReferenceProxy = false; |
||||
using value_type = std::conditional_t<std::is_const_v<T>, typename T::CProxy, |
||||
typename T::Proxy>; |
||||
using RemoveConst = MessageIteratorPolicy<std::remove_const_t<T>>; |
||||
using AddConst = MessageIteratorPolicy<const T>; |
||||
|
||||
struct Payload { |
||||
using Array = |
||||
std::conditional_t<std::is_const_v<T>, const upb_Array, upb_Array>; |
||||
upb_Message** arr; |
||||
upb_Arena* arena; |
||||
|
||||
void AddOffset(ptrdiff_t offset) { arr += offset; } |
||||
auto Get() const { |
||||
if constexpr (std::is_const_v<T>) { |
||||
return ::protos::internal::CreateMessage< |
||||
typename std::remove_const_t<T>>(*arr, arena); |
||||
} else { |
||||
return ::protos::internal::CreateMessageProxy<T>(*arr, arena); |
||||
} |
||||
} |
||||
auto Index() const { return arr; } |
||||
}; |
||||
}; |
||||
|
||||
} // namespace internal
|
||||
} // namespace protos
|
||||
|
||||
#endif // PROTOBUF_HPB_REPEATED_FIELD_ITERATOR_H_
|
@ -0,0 +1,17 @@ |
||||
#ifndef PROTOBUF_HPB_REQUIRES_H_ |
||||
#define PROTOBUF_HPB_REQUIRES_H_ |
||||
|
||||
#include <type_traits> |
||||
namespace protos::internal { |
||||
// Ports C++20 `requires` to C++17.
|
||||
// C++20 ideal:
|
||||
// if constexpr (requires { t.foo(); }) { ... }
|
||||
// Our C++17 stopgap solution:
|
||||
// if constexpr (Requires<T>([](auto x) -> decltype(x.foo()) {})) { ... }
|
||||
template <typename... T, typename F> |
||||
constexpr bool Requires(F) { |
||||
return std::is_invocable_v<F, T...>; |
||||
} |
||||
} // namespace protos::internal
|
||||
|
||||
#endif // PROTOBUF_HPB_REQUIRES_H_
|
Loading…
Reference in new issue