Move over upb/protos -> hpb (note that hpb is now a sibling of upb, not a child)

PiperOrigin-RevId: 647378884
pull/17239/head
Hong Shin 8 months ago committed by Copybara-Service
parent dfe3300c2f
commit d7087fc901
  1. 8
      .github/workflows/test_upb.yml
  2. 184
      hpb/BUILD
  3. 25
      hpb/bazel/BUILD
  4. 293
      hpb/bazel/upb_cc_proto_library.bzl
  5. 185
      hpb/protos.cc
  6. 564
      hpb/protos.h
  7. 2
      hpb/protos_extension_lock.cc
  8. 31
      hpb/protos_extension_lock.h
  9. 4
      hpb/protos_extension_lock_test.cc
  10. 25
      hpb/protos_internal.h
  11. 2
      hpb/protos_internal_test.cc
  12. 21
      hpb/protos_traits.h
  13. 300
      hpb/repeated_field.h
  14. 370
      hpb/repeated_field_iterator.h
  15. 2
      hpb/repeated_field_iterator_test.cc
  16. 17
      hpb/requires.h
  17. 232
      hpb_generator/tests/BUILD
  18. 259
      protos/BUILD
  19. 555
      protos/protos.h
  20. 24
      protos/protos_extension_lock.h
  21. 16
      protos/protos_internal.h
  22. 18
      protos/protos_traits.h
  23. 293
      protos/repeated_field.h
  24. 363
      protos/repeated_field_iterator.h

@ -40,7 +40,7 @@ jobs:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/sanitize:${{ matrix.config.bazel_version || '6.3.0' }}-75f2a85ece6526cc3d54087018c0f1097d78d42b
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: upb-bazel
bazel: test --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 //bazel/... //benchmarks/... //lua/... //protos/... //hpb_generator/... //python/... //upb/... //upb_generator/... ${{ matrix.config.flags }}
bazel: test --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 //bazel/... //benchmarks/... //lua/... //hpb_generator/... //python/... //upb/... //upb_generator/... ${{ matrix.config.flags }}
exclude-targets: ${{ matrix.config.exclude-targets }}
linux-gcc:
@ -59,7 +59,7 @@ jobs:
image: "us-docker.pkg.dev/protobuf-build/containers/test/linux/gcc:12.2-6.3.0-63dd26c0c7a808d92673a3e52e848189d4ab0f17"
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: "upb-bazel-gcc"
bazel: test --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 -c opt //bazel/... //benchmarks/... //lua/... //protos/... //hpb_generator/... //python/... //upb/... //upb_generator/...
bazel: test --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 -c opt //bazel/... //benchmarks/... //lua/... //hpb_generator/... //python/... //upb/... //upb_generator/...
windows:
strategy:
@ -80,7 +80,7 @@ jobs:
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: "upb-bazel-windows"
bazel: test --cxxopt=/std:c++17 --host_cxxopt=/std:c++17 //upb/... //upb_generator/... //python/... //protos/... //hpb_generator/...
bazel: test --cxxopt=/std:c++17 --host_cxxopt=/std:c++17 //upb/... //upb_generator/... //python/... //hpb_generator/...
version: 6.3.0
exclude-targets: -//python:conformance_test -//upb/reflection:def_builder_test
@ -107,7 +107,7 @@ jobs:
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: "upb-bazel-macos"
bazel: ${{ matrix.config.bazel-command }} --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 ${{ matrix.config.flags }} //bazel/... //benchmarks/... //lua/... //protos/... //hpb_generator/... //python/... //upb/... //upb_generator/...
bazel: ${{ matrix.config.bazel-command }} --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 ${{ matrix.config.flags }} //bazel/... //benchmarks/... //lua/... //hpb_generator/... //python/... //upb/... //upb_generator/...
version: 6.3.0
no-python:

@ -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_

@ -5,7 +5,7 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "protos/protos_extension_lock.h"
#include "google/protobuf/hpb/protos_extension_lock.h"
#include <atomic>

@ -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_

@ -5,7 +5,7 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "protos/protos_extension_lock.h"
#include "google/protobuf/hpb/protos_extension_lock.h"
#include <atomic>
#include <mutex>
@ -17,7 +17,7 @@
#include "absl/hash/hash.h"
#include "absl/log/absl_check.h"
#include "hpb_generator/tests/test_model.upb.proto.h"
#include "protos/protos.h"
#include "google/protobuf/hpb/protos.h"
#include "upb/mem/arena.hpp"
#ifndef ASSERT_OK

@ -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

@ -5,7 +5,7 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "protos/protos_internal.h"
#include "google/protobuf/hpb/protos_internal.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>

@ -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_

@ -5,7 +5,7 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "protos/repeated_field_iterator.h"
#include "google/protobuf/hpb/repeated_field_iterator.h"
#include <algorithm>
#include <array>

@ -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_

@ -5,99 +5,109 @@
# license that can be found in the LICENSE file or at
# https://developers.google.com/open-source/licenses/bsd
load(
"//bazel:cc_proto_library.bzl",
"cc_proto_library",
)
load(
"//bazel:upb_proto_library.bzl",
"upb_c_proto_library",
)
load(
"//protos/bazel:upb_cc_proto_library.bzl",
"upb_cc_proto_library",
)
load(
"//upb/bazel:build_defs.bzl",
"UPB_DEFAULT_CPPOPTS",
)
# todo: re-add post migration
# begin:google_only
# load(
# "//bazel:cc_proto_library.bzl",
# "cc_proto_library",
# )
# load(
# "//bazel:upb_proto_library.bzl",
# "upb_c_proto_library",
# )
# load(
# "//protos/bazel:upb_cc_proto_library.bzl",
# "upb_cc_proto_library",
# )
# load(
# "//upb/bazel:build_defs.bzl",
# "UPB_DEFAULT_CPPOPTS",
# )
# end:google_only
# begin:google_only
# package(default_applicable_licenses = ["//upb:license"])
# end:google_only
licenses(["notice"])
proto_library(
name = "test_model_proto",
srcs = [
"child_model.proto",
"test_enum.proto",
"test_extension.proto",
"test_model.proto",
],
)
proto_library(
name = "no_package_proto",
srcs = [
"no_package.proto",
],
)
proto_library(
name = "naming_conflict_proto",
srcs = [
"naming_conflict.proto",
],
)
proto_library(
name = "no_package_enum_user_proto",
srcs = [
"no_package_enum_user.proto",
],
deps = [":no_package_proto"],
)
upb_c_proto_library(
name = "test_model_upb_proto",
visibility = [
"//protos:__pkg__",
],
deps = [":test_model_proto"],
)
upb_cc_proto_library(
name = "test_model_upb_cc_proto",
visibility = ["//protos:__pkg__"],
deps = [":test_model_proto"],
)
upb_cc_proto_library(
name = "naming_conflict_upb_cc_proto",
visibility = ["//visibility:private"],
deps = [":naming_conflict_proto"],
)
upb_cc_proto_library(
name = "no_package_upb_cc_proto",
deps = [
":no_package_proto",
],
)
upb_cc_proto_library(
name = "no_package_enum_user_upb_cc_proto",
deps = [
":no_package_enum_user_proto",
],
)
cc_proto_library(
name = "test_model_cc_proto",
deps = [":test_model_proto"],
)
# todo: re-add post migration
# begin:google_only
# licenses(["notice"])
#
# proto_library(
# name = "test_model_proto",
# srcs = [
# "child_model.proto",
# "test_enum.proto",
# "test_extension.proto",
# "test_model.proto",
# ],
# )
#
# proto_library(
# name = "no_package_proto",
# srcs = [
# "no_package.proto",
# ],
# )
#
# proto_library(
# name = "naming_conflict_proto",
# srcs = [
# "naming_conflict.proto",
# ],
# )
#
# proto_library(
# name = "no_package_enum_user_proto",
# srcs = [
# "no_package_enum_user.proto",
# ],
# deps = [":no_package_proto"],
# )
#
# upb_c_proto_library(
# name = "test_model_upb_proto",
# visibility = [
# "//hpb:__pkg__",
# "//protos:__pkg__",
# ],
# deps = [":test_model_proto"],
# )
#
# upb_cc_proto_library(
# name = "test_model_upb_cc_proto",
# visibility = [
# "//hpb:__pkg__",
# "//protos:__pkg__",
# ],
# deps = [":test_model_proto"],
# )
#
# upb_cc_proto_library(
# name = "naming_conflict_upb_cc_proto",
# visibility = ["//visibility:private"],
# deps = [":naming_conflict_proto"],
# )
#
# upb_cc_proto_library(
# name = "no_package_upb_cc_proto",
# deps = [
# ":no_package_proto",
# ],
# )
#
# upb_cc_proto_library(
# name = "no_package_enum_user_upb_cc_proto",
# deps = [
# ":no_package_enum_user_proto",
# ],
# )
#
# cc_proto_library(
# name = "test_model_cc_proto",
# deps = [":test_model_proto"],
# )
# end:google_only
# begin:google_only
# proto_library(
@ -127,25 +137,27 @@ cc_proto_library(
# )
# end:google_only
cc_test(
name = "test_generated_cc_code",
srcs = ["test_generated.cc"],
copts = UPB_DEFAULT_CPPOPTS,
deps = [
# begin:google_only
# ":legacy_name_test_proto",
# end:google_only
":no_package_upb_cc_proto",
":test_model_upb_cc_proto",
":test_model_upb_proto",
":naming_conflict_upb_cc_proto",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"//protos",
"//protos:requires",
"//upb:mem",
"//protos:repeated_field",
],
)
# todo: re-add post migration
# begin:google_only
# cc_test(
# name = "test_generated_cc_code",
# srcs = ["test_generated.cc"],
# copts = UPB_DEFAULT_CPPOPTS,
# deps = [
# # google_only_begin_legacy_marker
# ":legacy_name_test_proto",
# # google_only_end_legacy_marker
# ":no_package_upb_cc_proto",
# ":test_model_upb_cc_proto",
# ":test_model_upb_proto",
# ":naming_conflict_upb_cc_proto",
# "@com_google_googletest//:gtest", "@com_google_googletest//:gtest_main",
# "@com_google_absl//absl/status:statusor",
# "@com_google_absl//absl/strings",
# "//protos",
# "//protos:requires",
# "//upb:mem",
# "//protos:repeated_field",
# ],
# )
# end:google_only

@ -5,171 +5,100 @@
# license that can be found in the LICENSE file or at
# https://developers.google.com/open-source/licenses/bsd
load(
"//protos/bazel:upb_cc_proto_library.bzl",
"upb_cc_proto_library_copts",
)
load(
"//upb/bazel:build_defs.bzl",
"UPB_DEFAULT_CPPOPTS",
)
# begin:google_only
# load(
# "//protos/bazel:upb_cc_proto_library.bzl",
# "upb_cc_proto_library_copts",
# )
# load(
# "//upb/bazel:build_defs.bzl",
# "UPB_DEFAULT_CPPOPTS",
# )
#
# package(default_applicable_licenses = ["//upb:license"])
#
# licenses(["notice"])
#
# cc_library(
# name = "repeated_field",
# hdrs = [
# "repeated_field.h",
# "repeated_field_iterator.h",
# ],
# copts = UPB_DEFAULT_CPPOPTS,
# visibility = ["//visibility:public"],
# deps = [
# "//hpb:repeated_field",
# ],
# )
#
# cc_library(
# name = "protos",
# hdrs = [
# "protos.h",
# ],
# copts = UPB_DEFAULT_CPPOPTS,
# visibility = ["//visibility:public"],
# deps = [
# "//hpb",
# ],
# )
#
# # Internally used type traits.
# cc_library(
# name = "protos_traits",
# hdrs = [
# "protos_traits.h",
# ],
# copts = UPB_DEFAULT_CPPOPTS,
# visibility = ["//visibility:private"],
# deps = [
# "//hpb:protos_traits",
# ],
# )
#
# cc_library(
# name = "protos_internal",
# hdrs = ["protos_internal.h"],
# copts = UPB_DEFAULT_CPPOPTS,
# visibility = ["//visibility:public"],
# deps = [
# "//hpb:protos_internal",
# ],
# )
#
# cc_library(
# name = "protos_extension_lock",
# hdrs = ["protos_extension_lock.h"],
# copts = UPB_DEFAULT_CPPOPTS,
# visibility = ["//visibility:public"],
# deps = [
# "//hpb:protos_extension_lock",
# ],
# )
#
# # 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",
# ],
# copts = UPB_DEFAULT_CPPOPTS,
# visibility = ["//visibility:public"],
# deps = [
# "//hpb:generated_protos_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me",
# ],
# )
#
# 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_library(
# name = "requires",
# hdrs = ["requires.h"],
# visibility = ["//visibility:public"],
# )
# end:google_only
licenses(["notice"])
cc_library(
name = "repeated_field",
hdrs = [
"repeated_field.h",
"repeated_field_iterator.h",
],
copts = UPB_DEFAULT_CPPOPTS,
visibility = ["//visibility:public"],
deps = [
":protos",
":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 = "protos",
srcs = [
"protos.cc",
],
hdrs = [
"protos.h",
],
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",
],
copts = UPB_DEFAULT_CPPOPTS,
visibility = ["//visibility:private"],
)
cc_library(
name = "protos_internal",
hdrs = ["protos_internal.h"],
copts = UPB_DEFAULT_CPPOPTS,
visibility = ["//visibility:public"],
deps = [
":protos",
"//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"],
copts = UPB_DEFAULT_CPPOPTS,
visibility = ["//visibility:public"],
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",
],
copts = UPB_DEFAULT_CPPOPTS,
visibility = ["//visibility:public"],
deps = [
":protos",
":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_generator/tests:test_model_upb_cc_proto",
"//protos",
"//protos:protos_extension_lock",
"//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"],
)

@ -7,558 +7,5 @@
#ifndef UPB_PROTOS_PROTOS_H_
#define UPB_PROTOS_PROTOS_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"
#include "google/protobuf/hpb/protos.h"
#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 // UPB_PROTOS_PROTOS_H_

@ -7,25 +7,5 @@
#ifndef UPB_PROTOS_PROTOS_EXTENSION_LOCK_H_
#define UPB_PROTOS_PROTOS_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 // UPB_PROTOS_PROTOS_EXTENSION_LOCK_H_
#include "google/protobuf/hpb/protos_extension_lock.h"
#endif

@ -7,19 +7,5 @@
#ifndef UPB_PROTOS_PROTOS_INTERNAL_H_
#define UPB_PROTOS_PROTOS_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
#include "google/protobuf/hpb/protos_internal.h"
#endif

@ -5,17 +5,7 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#ifndef THIRD_PARTY_UPB_PROTOS_PROTOS_TRAITS_H_
#define THIRD_PARTY_UPB_PROTOS_PROTOS_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 // THIRD_PARTY_UPB_PROTOS_PROTOS_TRAITS_H_
#ifndef UPB_PROTOS_PROTOS_TRAITS_H_
#define UPB_PROTOS_PROTOS_TRAITS_H_
#include "google/protobuf/hpb/protos_traits.h"
#endif

@ -7,294 +7,5 @@
#ifndef UPB_PROTOS_REPEATED_FIELD_H_
#define UPB_PROTOS_REPEATED_FIELD_H_
#include <assert.h>
#include <cstddef>
#include <iterator>
#include <type_traits>
#include "absl/strings/string_view.h"
#include "protos/protos.h"
#include "protos/protos_traits.h"
#include "protos/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 // UPB_PROTOS_REPEATED_FIELD_H_
#include "google/protobuf/hpb/repeated_field.h"
#endif

@ -7,364 +7,5 @@
#ifndef UPB_PROTOS_REPEATED_FIELD_ITERATOR_H_
#define UPB_PROTOS_REPEATED_FIELD_ITERATOR_H_
#include <cstddef>
#include <cstring>
#include <iterator>
#include <type_traits>
#include "absl/strings/string_view.h"
#include "protos/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 // UPB_PROTOS_REPEATED_FIELD_ITERATOR_H_
#include "google/protobuf/hpb/repeated_field_iterator.h"
#endif

Loading…
Cancel
Save