Merge branch 'master' into aarch64

pull/13171/head
Joshua Haberman 4 years ago
commit 103d51f102
  1. 29
      .github/workflows/cifuzz.yml
  2. 87
      BUILD
  3. 10
      README.md
  4. 8
      WORKSPACE
  5. 195
      bazel/ragel.BUILD
  6. 47
      bazel/upb_proto_library.bzl
  7. 4
      benchmarks/compare.py
  8. 8
      cmake/BUILD
  9. 40
      cmake/CMakeLists.txt
  10. 3433
      cmake/upb/json/parser.c
  11. 84
      tests/BUILD
  12. 7
      tests/bindings/lua/BUILD
  13. 10
      tests/bindings/lua/test.proto
  14. 118
      tests/bindings/lua/test_upb.lua
  15. 9
      tests/json/enum_from_separate_file.proto
  16. 47
      tests/json/test.proto
  17. BIN
      tests/json/test.proto.pb
  18. 336
      tests/json/test_json.cc
  19. 1194
      tests/pb/test_decoder.cc
  20. 128
      tests/pb/test_decoder.proto
  21. 102
      tests/pb/test_encoder.cc
  22. 926
      tests/test_cpp.cc
  23. 4
      tests/test_cpp.proto
  24. 69
      tests/test_generated_code.c
  25. 49
      tests/test_table.cc
  26. 1
      upb/bindings/lua/BUILD
  27. 46
      upb/bindings/lua/def.c
  28. 228
      upb/bindings/lua/msg.c
  29. 35
      upb/bindings/lua/upb.c
  30. 2
      upb/bindings/lua/upb.h
  31. 2
      upb/bindings/lua/upbc.cc
  32. 56
      upb/decode.c
  33. 2
      upb/decode.h
  34. 2
      upb/decode.int.h
  35. 217
      upb/def.c
  36. 10
      upb/def.h
  37. 5
      upb/def.hpp
  38. 117
      upb/encode.c
  39. 29
      upb/encode.h
  40. 923
      upb/handlers-inl.h
  41. 545
      upb/handlers.c
  42. 735
      upb/handlers.h
  43. 140
      upb/json/parser.h
  44. 2996
      upb/json/parser.rl
  45. 1396
      upb/json/printer.c
  46. 72
      upb/json/printer.h
  47. 21
      upb/json_decode.c
  48. 32
      upb/json_encode.c
  49. 117
      upb/msg.c
  50. 63
      upb/msg.h
  51. 919
      upb/pb/compile_decoder.c
  52. 1047
      upb/pb/decoder.c
  53. 242
      upb/pb/decoder.h
  54. 288
      upb/pb/decoder.int.h
  55. 563
      upb/pb/encoder.c
  56. 83
      upb/pb/encoder.h
  57. 36
      upb/pb/make-gdb-script.rb
  58. 339
      upb/pb/textprinter.c
  59. 69
      upb/pb/textprinter.h
  60. 74
      upb/pb/varint.c
  61. 164
      upb/pb/varint.int.h
  62. 13
      upb/port_def.inc
  63. 6
      upb/reflection.c
  64. 10
      upb/reflection.h
  65. 13
      upb/reflection.hpp
  66. 17
      upb/sink.c
  67. 517
      upb/sink.h
  68. 118
      upb/table.c
  69. 184
      upb/table.int.h
  70. 65
      upb/text_encode.c
  71. 5
      upb/text_encode.h
  72. 13
      upb/upb.h
  73. 30
      upbc/BUILD
  74. 65
      upbc/common.cc
  75. 66
      upbc/common.h
  76. 12
      upbc/generator.h
  77. 9
      upbc/main.cc
  78. 292
      upbc/protoc-gen-upb.cc
  79. 183
      upbc/protoc-gen-upbdefs.cc

@ -0,0 +1,29 @@
name: CIFuzz
on: [pull_request]
jobs:
Fuzzing:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
sanitizer: [address, undefined]
steps:
- name: Build Fuzzers (${{ matrix.sanitizer }})
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'upb'
dry-run: false
sanitizer: ${{ matrix.sanitizer }}
- name: Run Fuzzers (${{ matrix.sanitizer }})
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'upb'
fuzz-seconds: 600
dry-run: false
sanitizer: ${{ matrix.sanitizer }}
- name: Upload Crash
uses: actions/upload-artifact@v1
if: failure()
with:
name: ${{ matrix.sanitizer }}-artifacts
path: ./out/artifacts

87
BUILD

@ -149,6 +149,7 @@ cc_library(
"upb/def.h",
"upb/def.hpp",
"upb/reflection.h",
"upb/reflection.hpp",
],
copts = UPB_DEFAULT_COPTS,
visibility = ["//visibility:public"],
@ -187,7 +188,7 @@ cc_library(
"upb/json_encode.h",
],
copts = UPB_DEFAULT_COPTS,
visibility = ["//tests:__pkg__"],
visibility = ["//visibility:public"],
deps = [
":port",
":reflection",
@ -209,85 +210,6 @@ cc_library(
],
)
# Legacy C/C++ Libraries (not recommended for new code) ########################
cc_library(
name = "handlers",
srcs = [
"upb/handlers.c",
"upb/handlers-inl.h",
"upb/sink.c",
],
hdrs = [
"upb/handlers.h",
"upb/sink.h",
],
copts = UPB_DEFAULT_COPTS,
visibility = ["//tests:__pkg__"],
deps = [
":port",
":reflection",
":table",
":upb",
],
)
cc_library(
name = "upb_pb",
srcs = [
"upb/pb/compile_decoder.c",
"upb/pb/decoder.c",
"upb/pb/decoder.int.h",
"upb/pb/encoder.c",
"upb/pb/textprinter.c",
"upb/pb/varint.c",
"upb/pb/varint.int.h",
],
hdrs = [
"upb/pb/decoder.h",
"upb/pb/encoder.h",
"upb/pb/textprinter.h",
],
copts = UPB_DEFAULT_COPTS,
visibility = ["//tests:__pkg__"],
deps = [
":descriptor_upb_proto",
":handlers",
":port",
":reflection",
":table",
":upb",
],
)
# copybara:strip_for_google3_begin
cc_library(
name = "upb_json",
srcs = [
"upb/json/parser.c",
"upb/json/printer.c",
],
hdrs = [
"upb/json/parser.h",
"upb/json/printer.h",
],
copts = UPB_DEFAULT_COPTS,
visibility = ["//tests:__pkg__"],
deps = [
":upb",
":upb_pb",
],
)
genrule(
name = "generate_json_ragel",
srcs = ["//:upb/json/parser.rl"],
outs = ["upb/json/parser.c"],
cmd = "$(location @ragel//:ragelc) -C -o upb/json/parser.c $< && mv upb/json/parser.c $@",
tools = ["@ragel//:ragelc"],
visibility = ["//cmake:__pkg__"],
)
# Amalgamation #################################################################
py_binary(
@ -307,10 +229,7 @@ upb_amalgamation(
":fastdecode",
":descriptor_upb_proto",
":reflection",
":handlers",
":port",
":upb_pb",
":upb_json",
],
)
@ -406,5 +325,3 @@ filegroup(
]),
visibility = ["//cmake:__pkg__"],
)
# copybara:strip_end

@ -111,16 +111,6 @@ Then in your `.c` file you can #include the generated header:
/* Insert code that uses generated types. */
```
## Old "handlers" interfaces
This library contains several semi-deprecated interfaces (see BUILD
file for more info about which interfaces are deprecated). These
deprecated interfaces are still used in some significant projects,
such as the Ruby and PHP C bindings for protobuf in the [main protobuf
repo](https://github.com/protocolbuffers/protobuf). The goal is to
migrate the Ruby/PHP bindings to use the newer, simpler interfaces
instead. Please do not use the old interfaces in new code.
## Lua bindings
This repo has some Lua bindings for the core library. These are

@ -17,14 +17,6 @@ http_archive(
],
)
http_archive(
name = "ragel",
build_file = "//bazel:ragel.BUILD",
sha256 = "5f156edb65d20b856d638dd9ee2dfb43285914d9aa2b6ec779dac0270cd56c3f",
strip_prefix = "ragel-6.10",
urls = ["http://www.colm.net/files/ragel/ragel-6.10.tar.gz"],
)
http_archive(
name = "com_google_googletest",
urls = ["https://github.com/google/googletest/archive/b6cd405286ed8635ece71c72f118e659f4ade3fb.zip"], # 2019-01-07

@ -1,195 +0,0 @@
package(
default_visibility = ["//visibility:public"],
)
cc_binary(
name = "ragelc",
srcs = [
"ragel/rubycodegen.cpp",
"ragel/goipgoto.h",
"ragel/cdtable.h",
"ragel/rubycodegen.h",
"ragel/gotable.h",
"ragel/gocodegen.cpp",
"ragel/rubyfflat.cpp",
"ragel/common.cpp",
"ragel/gofflat.cpp",
"ragel/cdtable.cpp",
"ragel/cdsplit.cpp",
"ragel/rlparse.cpp",
"ragel/csfgoto.cpp",
"ragel/javacodegen.cpp",
"ragel/gocodegen.h",
"ragel/mlgoto.cpp",
"ragel/fsmgraph.cpp",
"ragel/version.h",
"ragel/mlfflat.h",
"ragel/fsmgraph.h",
"ragel/fsmbase.cpp",
"ragel/fsmstate.cpp",
"ragel/gotablish.cpp",
"ragel/rubyflat.cpp",
"ragel/cdfgoto.h",
"ragel/cscodegen.h",
"ragel/mlflat.cpp",
"ragel/rubyflat.h",
"ragel/goftable.h",
"ragel/rbxgoto.cpp",
"ragel/csfflat.cpp",
"ragel/gofgoto.cpp",
"ragel/gofgoto.h",
"ragel/ragel.h",
"ragel/goftable.cpp",
"ragel/cdcodegen.cpp",
"ragel/rlparse.h",
"ragel/cdsplit.h",
"ragel/xmlcodegen.cpp",
"ragel/goipgoto.cpp",
"ragel/dotcodegen.h",
"ragel/gogoto.cpp",
"ragel/csflat.h",
"ragel/csfflat.h",
#"ragel/config.h.in",
"ragel/csipgoto.cpp",
"ragel/mltable.cpp",
"ragel/mlflat.h",
"ragel/csftable.cpp",
"ragel/cdgoto.h",
"ragel/goflat.cpp",
"ragel/rubyfflat.h",
"ragel/mlftable.h",
"ragel/rubyftable.h",
"ragel/fsmap.cpp",
"ragel/redfsm.cpp",
"ragel/goflat.h",
"ragel/parsetree.cpp",
"ragel/fsmmin.cpp",
"ragel/dotcodegen.cpp",
"ragel/redfsm.h",
"ragel/mlcodegen.cpp",
"ragel/cdfgoto.cpp",
"ragel/cssplit.cpp",
"ragel/cstable.cpp",
"ragel/javacodegen.h",
"ragel/parsedata.cpp",
"ragel/buffer.h",
"ragel/gogoto.h",
"ragel/csgoto.h",
"ragel/pcheck.h",
"ragel/rubyftable.cpp",
"ragel/csfgoto.h",
"ragel/common.h",
"ragel/cdftable.h",
"ragel/mlgoto.h",
"ragel/csgoto.cpp",
"ragel/cdflat.h",
"ragel/cdipgoto.h",
"ragel/cstable.h",
"ragel/gendata.h",
"ragel/cdfflat.cpp",
"ragel/gotable.cpp",
"ragel/cdcodegen.h",
"ragel/gendata.cpp",
"ragel/rubytable.h",
"ragel/csflat.cpp",
"ragel/inputdata.h",
"ragel/inputdata.cpp",
"ragel/rubytable.cpp",
"ragel/fsmattach.cpp",
"ragel/csipgoto.h",
"ragel/cscodegen.cpp",
"ragel/cdfflat.h",
"ragel/rbxgoto.h",
"ragel/xmlcodegen.h",
"ragel/gofflat.h",
"ragel/parsedata.h",
"ragel/mlfgoto.h",
"ragel/cdflat.cpp",
"ragel/config.h",
"ragel/rlscan.cpp",
"ragel/mlcodegen.h",
"ragel/mlfflat.cpp",
"ragel/mlftable.cpp",
"ragel/mltable.h",
"ragel/cdipgoto.cpp",
"ragel/cdftable.cpp",
"ragel/parsetree.h",
"ragel/rlscan.h",
"ragel/main.cpp",
"ragel/cssplit.h",
"ragel/mlfgoto.cpp",
"ragel/csftable.h",
"ragel/gotablish.h",
"ragel/cdgoto.cpp",
"aapl/avlmelkey.h",
"aapl/dlistmel.h",
"aapl/avliset.h",
"aapl/avlkeyless.h",
"aapl/sbstset.h",
"aapl/sbsttable.h",
"aapl/quicksort.h",
"aapl/avlitree.h",
"aapl/avlcommon.h",
"aapl/bstset.h",
"aapl/avlmel.h",
"aapl/insertsort.h",
"aapl/dlist.h",
"aapl/avlmap.h",
"aapl/mergesort.h",
"aapl/resize.h",
"aapl/bstcommon.h",
"aapl/bstmap.h",
"aapl/compare.h",
"aapl/svector.h",
"aapl/avlset.h",
"aapl/bsttable.h",
"aapl/avlikeyless.h",
"aapl/bubblesort.h",
"aapl/table.h",
"aapl/avlbasic.h",
"aapl/vector.h",
"aapl/avlimap.h",
"aapl/dlistval.h",
"aapl/dlcommon.h",
"aapl/avlibasic.h",
"aapl/sbstmap.h",
"aapl/avlimel.h",
"aapl/avlimelkey.h",
"aapl/avltree.h",
],
includes = [
"aapl",
"ragel",
],
)
config_h_contents = """
#define PACKAGE "ragel"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME "ragel"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "ragel 6.10"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "ragel"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "6.10"
/* Version number of package */
#define VERSION "6.10"
"""
genrule(
name = "gen_config_h",
outs = ["ragel/config.h"],
cmd = "(cat <<'HEREDOC'\n%s\nHEREDOC\n) > $@" % config_h_contents,
)

@ -153,26 +153,29 @@ _UpbDefsWrappedCcInfo = provider(fields = ["cc_info"])
_WrappedGeneratedSrcsInfo = provider(fields = ["srcs"])
_WrappedDefsGeneratedSrcsInfo = provider(fields = ["srcs"])
def _compile_upb_protos(ctx, proto_info, proto_sources, ext):
def _compile_upb_protos(ctx, generator, proto_info, proto_sources):
if len(proto_sources) == 0:
return GeneratedSrcsInfo(srcs = [], hdrs = [])
ext = "." + generator
tool = getattr(ctx.executable, "_gen_" + generator)
srcs = [_generate_output_file(ctx, name, ext + ".c") for name in proto_sources]
hdrs = [_generate_output_file(ctx, name, ext + ".h") for name in proto_sources]
transitive_sets = proto_info.transitive_descriptor_sets.to_list()
fasttable_enabled = ctx.attr._fasttable_enabled[_FastTableEnabled].enabled
fasttable_enabled = (hasattr(ctx.attr, "_fasttable_enabled") and
ctx.attr._fasttable_enabled[_FastTableEnabled].enabled)
codegen_params = "fasttable:" if fasttable_enabled else ""
ctx.actions.run(
inputs = depset(
direct = [proto_info.direct_descriptor_set],
transitive = [proto_info.transitive_descriptor_sets],
),
tools = [ctx.executable._upbc],
tools = [tool],
outputs = srcs + hdrs,
executable = ctx.executable._protoc,
arguments = [
"--upb_out=" + codegen_params + _get_real_root(srcs[0]),
"--plugin=protoc-gen-upb=" + ctx.executable._upbc.path,
"--" + generator + "_out=" + codegen_params + _get_real_root(srcs[0]),
"--plugin=protoc-gen-" + generator + "=" + tool.path,
"--descriptor_set_in=" + ctx.configuration.host_path_separator.join([f.path for f in transitive_sets]),
] +
[_get_real_short_path(file) for file in proto_sources],
@ -213,22 +216,20 @@ def _upb_proto_rule_impl(ctx):
cc_info,
]
def _upb_proto_aspect_impl(target, ctx, cc_provider, file_provider):
def _upb_proto_aspect_impl(target, ctx, generator, cc_provider, file_provider):
proto_info = target[ProtoInfo]
files = _compile_upb_protos(ctx, proto_info, proto_info.direct_sources, ctx.attr._ext)
deps = ctx.rule.attr.deps + ctx.attr._upb
if cc_provider == _UpbDefsWrappedCcInfo:
deps += ctx.attr._upb_reflection
files = _compile_upb_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[_UpbDefsWrappedCcInfo].cc_info for dep in deps if _UpbDefsWrappedCcInfo in dep]
if cc_provider == _UpbDefsWrappedCcInfo:
if generator == "upbdefs":
if _UpbWrappedCcInfo not in target:
fail("Target should have _UpbDefsWrappedCcInfo provider")
dep_ccinfos += [target[_UpbWrappedCcInfo].cc_info]
cc_info = _cc_library_func(
ctx = ctx,
name = ctx.rule.attr.name + ctx.attr._ext,
name = ctx.rule.attr.name + "." + generator,
hdrs = files.hdrs,
srcs = files.srcs,
copts = ctx.attr._copts[_UpbProtoLibraryCopts].copts,
@ -237,10 +238,10 @@ def _upb_proto_aspect_impl(target, ctx, cc_provider, file_provider):
return [cc_provider(cc_info = cc_info), file_provider(srcs = files)]
def _upb_proto_library_aspect_impl(target, ctx):
return _upb_proto_aspect_impl(target, ctx, _UpbWrappedCcInfo, _WrappedGeneratedSrcsInfo)
return _upb_proto_aspect_impl(target, ctx, "upb", _UpbWrappedCcInfo, _WrappedGeneratedSrcsInfo)
def _upb_proto_reflection_library_aspect_impl(target, ctx):
return _upb_proto_aspect_impl(target, ctx, _UpbDefsWrappedCcInfo, _WrappedDefsGeneratedSrcsInfo)
return _upb_proto_aspect_impl(target, ctx, "upbdefs", _UpbDefsWrappedCcInfo, _WrappedDefsGeneratedSrcsInfo)
def _maybe_add(d):
if not _is_bazel:
@ -258,7 +259,7 @@ _upb_proto_library_aspect = aspect(
"_copts": attr.label(
default = "//:upb_proto_library_copts__for_generated_code_only_do_not_use",
),
"_upbc": attr.label(
"_gen_upb": attr.label(
executable = True,
cfg = "host",
default = "//upbc:protoc-gen-upb",
@ -275,7 +276,6 @@ _upb_proto_library_aspect = aspect(
"//:generated_code_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me",
"//:upb",
]),
"_ext": attr.string(default = ".upb"),
"_fasttable_enabled": attr.label(default = "//:fasttable_enabled"),
}),
implementation = _upb_proto_library_aspect_impl,
@ -308,10 +308,10 @@ _upb_proto_reflection_library_aspect = aspect(
"_copts": attr.label(
default = "//:upb_proto_library_copts__for_generated_code_only_do_not_use",
),
"_upbc": attr.label(
"_gen_upbdefs": attr.label(
executable = True,
cfg = "host",
default = "//upbc:protoc-gen-upb",
default = "//upbc:protoc-gen-upbdefs",
),
"_protoc": attr.label(
executable = True,
@ -321,22 +321,13 @@ _upb_proto_reflection_library_aspect = aspect(
"_cc_toolchain": attr.label(
default = "@bazel_tools//tools/cpp:current_cc_toolchain",
),
# For unknown reasons, this gets overwritten.
"_upb": attr.label_list(
"_upbdefs": attr.label_list(
default = [
"//:generated_code_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me",
"//:upb",
"//:reflection",
],
),
"_upb_reflection": attr.label_list(
default = [
"//:upb",
"//:reflection",
],
),
"_ext": attr.string(default = ".upbdefs"),
"_fasttable_enabled": attr.label(default = "//:fasttable_enabled"),
}),
implementation = _upb_proto_reflection_library_aspect_impl,
provides = [

@ -45,7 +45,9 @@ def Benchmark(outbase, bench_cpu=True, runs=12, fasttable=False):
# Translate into the format expected by benchstat.
with open(outbase + ".txt", "w") as f:
for run in bench_json["benchmarks"]:
name = re.sub(r'^BM_', 'Benchmark', run["name"])
name = run["name"]
name = name.replace(" ", "")
name = re.sub(r'^BM_', 'Benchmark', name)
if name.endswith("_mean") or name.endswith("_median") or name.endswith("_stddev"):
continue
values = (name, run["iterations"], run["cpu_time"])

@ -36,13 +36,6 @@ genrule(
tools = [":make_cmakelists"],
)
genrule(
name = "copy_json_ragel",
srcs = ["//:upb/json/parser.c"],
outs = ["generated-in/upb/json/parser.c"],
cmd = "cp $< $@",
)
genrule(
name = "copy_protos",
srcs = ["//:descriptor_upb_proto"],
@ -59,7 +52,6 @@ generated_file_staleness_test(
"CMakeLists.txt",
"google/protobuf/descriptor.upb.c",
"google/protobuf/descriptor.upb.h",
"upb/json/parser.c",
],
generated_pattern = "generated-in/%s",
)

@ -99,7 +99,8 @@ add_library(reflection
../upb/reflection.c
../upb/def.h
../upb/def.hpp
../upb/reflection.h)
../upb/reflection.h
../upb/reflection.hpp)
target_link_libraries(reflection
descriptor_upb_proto
port
@ -123,43 +124,6 @@ target_link_libraries(json
add_library(table INTERFACE)
target_link_libraries(table INTERFACE
port)
add_library(handlers
../upb/handlers.c
../upb/handlers-inl.h
../upb/sink.c
../upb/handlers.h
../upb/sink.h)
target_link_libraries(handlers
port
reflection
table
upb)
add_library(upb_pb
../upb/pb/compile_decoder.c
../upb/pb/decoder.c
../upb/pb/decoder.int.h
../upb/pb/encoder.c
../upb/pb/textprinter.c
../upb/pb/varint.c
../upb/pb/varint.int.h
../upb/pb/decoder.h
../upb/pb/encoder.h
../upb/pb/textprinter.h)
target_link_libraries(upb_pb
descriptor_upb_proto
handlers
port
reflection
table
upb)
add_library(upb_json
../cmake/upb/json/parser.c
../upb/json/printer.c
../upb/json/parser.h
../upb/json/printer.h)
target_link_libraries(upb_json
upb
upb_pb)
add_library(wyhash INTERFACE)

File diff suppressed because it is too large Load Diff

@ -29,7 +29,6 @@ cc_library(
],
copts = UPB_DEFAULT_CPPOPTS,
deps = [
"//:handlers",
"//:port",
"//:upb",
],
@ -76,32 +75,6 @@ upb_proto_library(
deps = ["@com_google_protobuf//:test_messages_proto3_proto"],
)
proto_library(
name = "test_decoder_proto",
srcs = [
"pb/test_decoder.proto",
],
)
upb_proto_reflection_library(
name = "test_decoder_upb_proto",
deps = [":test_decoder_proto"],
)
cc_test(
name = "test_decoder",
srcs = ["pb/test_decoder.cc"],
copts = UPB_DEFAULT_CPPOPTS,
deps = [
":test_decoder_upb_proto",
":upb_test",
"//:handlers",
"//:port",
"//:upb",
"//:upb_pb",
],
)
proto_library(
name = "test_cpp_proto",
srcs = [
@ -121,11 +94,9 @@ cc_test(
deps = [
":test_cpp_upb_proto",
":upb_test",
"//:handlers",
"//:port",
"//:reflection",
"//:upb",
"//:upb_pb",
],
)
@ -160,61 +131,6 @@ cc_binary(
],
)
# copybara:strip_for_google3_begin
cc_test(
name = "test_encoder",
srcs = ["pb/test_encoder.cc"],
copts = UPB_DEFAULT_CPPOPTS,
deps = [
":upb_test",
"//:descriptor_upb_proto",
"//:descriptor_upb_proto_reflection",
"//:upb",
"//:upb_pb",
],
)
proto_library(
name = "test_json_enum_from_separate",
srcs = ["json/enum_from_separate_file.proto"],
deps = [":test_json_proto"],
)
proto_library(
name = "test_json_proto",
srcs = ["json/test.proto"],
)
upb_proto_reflection_library(
name = "test_json_upb_proto_reflection",
deps = ["test_json_proto"],
)
upb_proto_library(
name = "test_json_enum_from_separate_upb_proto",
deps = [":test_json_enum_from_separate"],
)
upb_proto_library(
name = "test_json_upb_proto",
deps = [":test_json_proto"],
)
cc_test(
name = "test_json",
srcs = [
"json/test_json.cc",
],
copts = UPB_DEFAULT_CPPOPTS,
deps = [
":test_json_upb_proto",
":test_json_upb_proto_reflection",
":upb_test",
"//:upb_json",
],
)
# copybara:strip_end
upb_proto_library(
name = "conformance_proto_upb",
testonly = 1,

@ -16,6 +16,7 @@ cc_test(
data = [
"test_upb.lua",
":descriptor_proto_lua",
":empty_proto_lua",
":test_messages_proto2_proto_lua",
":test_messages_proto3_proto_lua",
":test_proto_lua",
@ -36,6 +37,7 @@ proto_library(
name = "test_proto",
testonly = 1,
srcs = ["test.proto"],
deps = ["@com_google_protobuf//:timestamp_proto"],
)
lua_proto_library(
@ -49,6 +51,11 @@ lua_proto_library(
deps = ["@com_google_protobuf//:descriptor_proto"],
)
lua_proto_library(
name = "empty_proto_lua",
deps = ["@com_google_protobuf//:empty_proto"],
)
lua_proto_library(
name = "test_messages_proto3_proto_lua",
testonly = 1,

@ -1,6 +1,8 @@
syntax = "proto2";
import "google/protobuf/timestamp.proto";
package upb_test;
message MapTest {
@ -22,3 +24,11 @@ message UnpackedTest {
repeated fixed32 f32_packed = 4 [packed = false];
repeated fixed64 f64_packed = 5 [packed = false];
}
message TestLargeFieldNumber {
optional int32 i32 = 456214797;
}
message TestTimestamp {
optional google.protobuf.Timestamp ts = 1;
}

@ -5,6 +5,7 @@ local upb_test = require "tests.bindings.lua.test_pb"
local test_messages_proto3 = require "google.protobuf.test_messages_proto3_pb"
local test_messages_proto2 = require "google.protobuf.test_messages_proto2_pb"
local descriptor = require "google.protobuf.descriptor_pb"
local empty = require "google.protobuf.empty_pb"
if _VERSION >= 'Lua 5.2' then
_ENV = lunit.module("testupb", "seeall")
@ -91,6 +92,69 @@ function test_msg_map()
assert_equal(12, msg2.map_int32_int32[6])
end
function test_map_sorting()
function msg_with_int32_entries(start, expand)
local msg = test_messages_proto3.TestAllTypesProto3()
for i=start,start + 8 do
msg.map_int32_int32[i] = i * 2
end
if expand then
for i=start+20,200 do
msg.map_int32_int32[i] = i
end
for i=start+20,200 do
msg.map_int32_int32[i] = nil
end
end
return msg
end
function msg_with_msg_entries(expand)
local msg = test_messages_proto3.TestAllTypesProto3()
-- 8! = 40320 possible orderings makes it overwhelmingly likely that two
-- random orderings will be different.
for i=1,8 do
local submsg = test_messages_proto3.TestAllTypesProto3.NestedMessage()
submsg.corecursive = msg_with_int32_entries(i, expand)
msg.map_string_nested_message[tostring(i)] = submsg
end
expand = false
if expand then
for i=21,2000 do
local submsg = test_messages_proto3.TestAllTypesProto3.NestedMessage()
submsg.corecursive = msg_with_int32_entries(i, expand)
msg.map_string_nested_message[tostring(i)] = submsg
end
for i=21,2000 do
msg.map_string_nested_message[tostring(i)] = nil
end
end
return msg
end
-- Create two messages with the same contents but (hopefully) different
-- map table orderings.
local msg = msg_with_msg_entries(false)
local msg2 = msg_with_msg_entries(true)
local text1 = upb.text_encode(msg)
local text2 = upb.text_encode(msg2)
assert_equal(text1, text2)
local binary1 = upb.encode(msg, {upb.ENCODE_DETERMINISTIC})
local binary2 = upb.encode(msg2, {upb.ENCODE_DETERMINISTIC})
assert_equal(binary1, binary2)
-- Non-sorted map should compare different.
local text3 = upb.text_encode(msg, {upb.TXTENC_NOSORT})
assert_not_equal(text1, text3)
local binary3 = upb.encode(msg)
assert_not_equal(binary1, binary3)
end
function test_utf8()
local proto2_msg = test_messages_proto2.TestAllTypesProto2()
proto2_msg.optional_string = "\xff"
@ -587,6 +651,20 @@ function test_foo()
assert_equal(set.file[1].name, "google/protobuf/descriptor.proto")
end
function test_descriptor()
local symtab = upb.SymbolTable()
local file_proto = descriptor.FileDescriptorProto {
name = "test.proto",
message_type = upb.Array(descriptor.DescriptorProto, {
descriptor.DescriptorProto{
name = "ABC",
},
})
}
local file = symtab:add_file(upb.encode(file_proto))
assert_equal(file:symtab(), symtab)
end
function test_descriptor_error()
local symtab = upb.SymbolTable()
local file = descriptor.FileDescriptorProto()
@ -601,6 +679,46 @@ function test_descriptor_error()
assert_nil(symtab:lookup_msg("ABC"))
end
function test_encode_skipunknown()
-- Test that upb.ENCODE_SKIPUNKNOWN does not encode unknown fields.
local msg = test_messages_proto3.TestAllTypesProto3{
optional_int32 = 10,
optional_uint32 = 20,
optional_int64 = 30,
}
-- SKIPUNKNOWN here tests that it does *not* affect regular fields.
local serialized = upb.encode(msg, {upb.ENCODE_SKIPUNKNOWN})
assert_true(#serialized > 0)
local empty_with_unknown = upb.decode(empty.Empty, serialized)
assert_true(#upb.encode(empty_with_unknown) > 0)
-- Verify that unknown fields are not serialized.
assert_true(#upb.encode(empty_with_unknown, {upb.ENCODE_SKIPUNKNOWN}) == 0)
end
function test_json_emit_defaults()
local msg = test_messages_proto3.TestAllTypesProto3()
local json = upb.json_encode(msg, {upb.JSONENC_EMITDEFAULTS})
end
function test_encode_depth_limit()
local msg = test_messages_proto3.TestAllTypesProto3()
msg.recursive_message = msg
assert_error(function() upb.encode(msg) end)
end
function test_large_field_number()
local msg = upb_test.TestLargeFieldNumber()
msg.i32 = 5
local serialized = upb.encode(msg)
local msg2 = upb.decode(upb_test.TestLargeFieldNumber, serialized)
assert_equal(msg.i32, msg2.i32)
end
function test_timestamp_minutes()
local msg = upb.json_decode(upb_test.TestTimestamp, '{"ts": "2000-01-01T00:00:00-06:59"}')
assert_equal(msg.ts.seconds, 946684800 + ((6 * 60) + 59) * 60)
end
function test_gc()
local top = test_messages_proto3.TestAllTypesProto3()
local n = 100

@ -1,9 +0,0 @@
syntax = "proto2";
import "tests/json/test.proto";
package upb.test.json;
message ImportEnum {
optional MyEnum e = 1;
}

@ -1,47 +0,0 @@
syntax = "proto3";
package upb.test.json;
message TestMessage {
int32 optional_int32 = 1;
int64 optional_int64 = 2;
int32 optional_uint32 = 3;
int64 optional_uint64 = 4;
string optional_string = 5;
bytes optional_bytes = 6;
bool optional_bool = 7;
SubMessage optional_msg = 8;
MyEnum optional_enum = 9;
repeated int32 repeated_int32 = 11;
repeated int64 repeated_int64 = 12;
repeated uint32 repeated_uint32 = 13;
repeated uint64 repeated_uint64 = 14;
repeated string repeated_string = 15;
repeated bytes repeated_bytes = 16;
repeated bool repeated_bool = 17;
repeated SubMessage repeated_msg = 18;
repeated MyEnum repeated_enum = 19;
map<string, string> map_string_string = 20;
map<int32, string> map_int32_string = 21;
map<bool, string> map_bool_string = 22;
map<string, int32> map_string_int32 = 23;
map<string, bool> map_string_bool = 24;
map<string, SubMessage> map_string_msg = 25;
oneof o {
int32 oneof_int32 = 26;
int64 oneof_int64 = 27;
}
}
message SubMessage {
int32 foo = 1;
}
enum MyEnum {
A = 0;
B = 1;
C = 2;
}

Binary file not shown.

@ -1,336 +0,0 @@
/*
*
* A set of tests for JSON parsing and serialization.
*/
#include <string>
#include "tests/json/test.upb.h" // Test that it compiles for C++.
#include "tests/json/test.upbdefs.h"
#include "tests/test_util.h"
#include "tests/upb_test.h"
#include "upb/def.hpp"
#include "upb/handlers.h"
#include "upb/json/parser.h"
#include "upb/json/printer.h"
#include "upb/port_def.inc"
#include "upb/upb.h"
// Macros for readability in test case list: allows us to give TEST("...") /
// EXPECT("...") pairs.
#define TEST(x) x
#define EXPECT_SAME NULL
#define EXPECT(x) x
#define TEST_SENTINEL { NULL, NULL }
struct TestCase {
const char* input;
const char* expected;
};
bool verbose = false;
static TestCase kTestRoundtripMessages[] = {
// Test most fields here.
{
TEST("{\"optionalInt32\":-42,\"optionalString\":\"Test\\u0001Message\","
"\"optionalMsg\":{\"foo\":42},"
"\"optionalBool\":true,\"repeatedMsg\":[{\"foo\":1},"
"{\"foo\":2}]}"),
EXPECT_SAME
},
// We must also recognize raw proto names.
{
TEST("{\"optional_int32\":-42,\"optional_string\":\"Test\\u0001Message\","
"\"optional_msg\":{\"foo\":42},"
"\"optional_bool\":true,\"repeated_msg\":[{\"foo\":1},"
"{\"foo\":2}]}"),
EXPECT("{\"optionalInt32\":-42,\"optionalString\":\"Test\\u0001Message\","
"\"optionalMsg\":{\"foo\":42},"
"\"optionalBool\":true,\"repeatedMsg\":[{\"foo\":1},"
"{\"foo\":2}]}")
},
// Test special escapes in strings.
{
TEST("{\"repeatedString\":[\"\\b\",\"\\r\",\"\\n\",\"\\f\",\"\\t\","
"\"\uFFFF\"]}"),
EXPECT_SAME
},
// Test enum symbolic names.
{
// The common case: parse and print the symbolic name.
TEST("{\"optionalEnum\":\"A\"}"),
EXPECT_SAME
},
{
// Unknown enum value: will be printed as an integer.
TEST("{\"optionalEnum\":42}"),
EXPECT_SAME
},
{
// Known enum value: we're happy to parse an integer but we will re-emit the
// symbolic name.
TEST("{\"optionalEnum\":1}"),
EXPECT("{\"optionalEnum\":\"B\"}")
},
// UTF-8 tests: escapes -> literal UTF8 in output.
{
// Note double escape on \uXXXX: we want the escape to be processed by the
// JSON parser, not by the C++ compiler!
TEST("{\"optionalString\":\"\\u007F\"}"),
EXPECT("{\"optionalString\":\"\x7F\"}")
},
{
TEST("{\"optionalString\":\"\\u0080\"}"),
EXPECT("{\"optionalString\":\"\xC2\x80\"}")
},
{
TEST("{\"optionalString\":\"\\u07FF\"}"),
EXPECT("{\"optionalString\":\"\xDF\xBF\"}")
},
{
TEST("{\"optionalString\":\"\\u0800\"}"),
EXPECT("{\"optionalString\":\"\xE0\xA0\x80\"}")
},
{
TEST("{\"optionalString\":\"\\uFFFF\"}"),
EXPECT("{\"optionalString\":\"\xEF\xBF\xBF\"}")
},
// map-field tests
{
TEST("{\"mapStringString\":{\"a\":\"value1\",\"b\":\"value2\","
"\"c\":\"value3\"}}"),
EXPECT_SAME
},
{
TEST("{\"mapInt32String\":{\"1\":\"value1\",\"-1\":\"value2\","
"\"1234\":\"value3\"}}"),
EXPECT_SAME
},
{
TEST("{\"mapBoolString\":{\"false\":\"value1\",\"true\":\"value2\"}}"),
EXPECT_SAME
},
{
TEST("{\"mapStringInt32\":{\"asdf\":1234,\"jkl;\":-1}}"),
EXPECT_SAME
},
{
TEST("{\"mapStringBool\":{\"asdf\":true,\"jkl;\":false}}"),
EXPECT_SAME
},
{
TEST("{\"mapStringMsg\":{\"asdf\":{\"foo\":42},\"jkl;\":{\"foo\":84}}}"),
EXPECT_SAME
},
TEST_SENTINEL
};
static TestCase kTestRoundtripMessagesPreserve[] = {
// Test most fields here.
{
TEST("{\"optional_int32\":-42,\"optional_string\":\"Test\\u0001Message\","
"\"optional_msg\":{\"foo\":42},"
"\"optional_bool\":true,\"repeated_msg\":[{\"foo\":1},"
"{\"foo\":2}]}"),
EXPECT_SAME
},
TEST_SENTINEL
};
static TestCase kTestSkipUnknown[] = {
{
TEST("{\"optionalEnum\":\"UNKNOWN_ENUM_VALUE\"}"),
EXPECT("{}"),
},
TEST_SENTINEL
};
static TestCase kTestFailure[] = {
{
TEST("{\"optionalEnum\":\"UNKNOWN_ENUM_VALUE\"}"),
EXPECT("{}"), /* Actually we expect error, this is checked later. */
},
TEST_SENTINEL
};
class StringSink {
public:
StringSink() {
upb_byteshandler_init(&byteshandler_);
upb_byteshandler_setstring(&byteshandler_, &str_handler, NULL);
upb_bytessink_reset(&bytessink_, &byteshandler_, &s_);
}
~StringSink() { }
upb_bytessink Sink() { return bytessink_; }
const std::string& Data() { return s_; }
private:
static size_t str_handler(void* _closure, const void* hd,
const char* data, size_t len,
const upb_bufhandle* handle) {
UPB_UNUSED(hd);
UPB_UNUSED(handle);
std::string* s = static_cast<std::string*>(_closure);
std::string appended(data, len);
s->append(data, len);
return len;
}
upb_byteshandler byteshandler_;
upb_bytessink bytessink_;
std::string s_;
};
void test_json_roundtrip_message(const char* json_src,
const char* json_expected,
const upb::Handlers* serialize_handlers,
const upb::json::ParserMethodPtr parser_method,
int seam,
bool ignore_unknown) {
VerboseParserEnvironment env(verbose);
StringSink data_sink;
upb::json::PrinterPtr printer = upb::json::PrinterPtr::Create(
env.arena(), serialize_handlers, data_sink.Sink());
upb::json::ParserPtr parser = upb::json::ParserPtr::Create(
env.arena(), parser_method, NULL, printer.input(),
env.status(), ignore_unknown);
env.ResetBytesSink(parser.input());
env.Reset(json_src, strlen(json_src), false, false);
bool ok = env.Start() &&
env.ParseBuffer(seam) &&
env.ParseBuffer(-1) &&
env.End();
ASSERT(ok);
ASSERT(env.CheckConsistency());
if (memcmp(json_expected,
data_sink.Data().data(),
data_sink.Data().size())) {
fprintf(stderr,
"JSON parse/serialize roundtrip result differs:\n"
"Expected:\n%s\nParsed/Serialized:\n%s\n",
json_expected, data_sink.Data().c_str());
abort();
}
}
// Starts with a message in JSON format, parses and directly serializes again,
// and compares the result.
void test_json_roundtrip() {
upb::SymbolTable symtab;
upb::HandlerCache serialize_handlercache(
upb::json::PrinterPtr::NewCache(false));
upb::json::CodeCache parse_codecache;
upb::MessageDefPtr md(upb_test_json_TestMessage_getmsgdef(symtab.ptr()));
ASSERT(md);
const upb::Handlers* serialize_handlers = serialize_handlercache.Get(md);
const upb::json::ParserMethodPtr parser_method = parse_codecache.Get(md);
ASSERT(serialize_handlers);
for (const TestCase* test_case = kTestRoundtripMessages;
test_case->input != NULL; test_case++) {
const char *expected =
(test_case->expected == EXPECT_SAME) ?
test_case->input :
test_case->expected;
for (size_t i = 0; i < strlen(test_case->input); i++) {
test_json_roundtrip_message(test_case->input, expected,
serialize_handlers, parser_method, (int)i,
false);
}
}
// Tests ignore unknown.
for (const TestCase* test_case = kTestSkipUnknown;
test_case->input != NULL; test_case++) {
const char *expected =
(test_case->expected == EXPECT_SAME) ?
test_case->input :
test_case->expected;
for (size_t i = 0; i < strlen(test_case->input); i++) {
test_json_roundtrip_message(test_case->input, expected,
serialize_handlers, parser_method, (int)i,
true);
}
}
serialize_handlercache = upb::json::PrinterPtr::NewCache(true);
serialize_handlers = serialize_handlercache.Get(md);
for (const TestCase* test_case = kTestRoundtripMessagesPreserve;
test_case->input != NULL; test_case++) {
const char *expected =
(test_case->expected == EXPECT_SAME) ?
test_case->input :
test_case->expected;
for (size_t i = 0; i < strlen(test_case->input); i++) {
test_json_roundtrip_message(test_case->input, expected,
serialize_handlers, parser_method, (int)i,
false);
}
}
}
void test_json_parse_failure(const char* json_src,
const upb::Handlers* serialize_handlers,
const upb::json::ParserMethodPtr parser_method,
int seam) {
VerboseParserEnvironment env(verbose);
StringSink data_sink;
upb::json::PrinterPtr printer = upb::json::PrinterPtr::Create(
env.arena(), serialize_handlers, data_sink.Sink());
upb::json::ParserPtr parser = upb::json::ParserPtr::Create(
env.arena(), parser_method, NULL, printer.input(), env.status(), false);
env.ResetBytesSink(parser.input());
env.Reset(json_src, strlen(json_src), false, true);
bool ok = env.Start() &&
env.ParseBuffer(seam) &&
env.ParseBuffer(-1) &&
env.End();
ASSERT(!ok);
ASSERT(env.CheckConsistency());
}
// Starts with a proto message in JSON format, parses and expects failre.
void test_json_failure() {
upb::SymbolTable symtab;
upb::HandlerCache serialize_handlercache(
upb::json::PrinterPtr::NewCache(false));
upb::json::CodeCache parse_codecache;
upb::MessageDefPtr md(upb_test_json_TestMessage_getmsgdef(symtab.ptr()));
ASSERT(md);
const upb::Handlers* serialize_handlers = serialize_handlercache.Get(md);
const upb::json::ParserMethodPtr parser_method = parse_codecache.Get(md);
ASSERT(serialize_handlers);
for (const TestCase* test_case = kTestFailure;
test_case->input != NULL; test_case++) {
for (size_t i = 0; i < strlen(test_case->input); i++) {
test_json_parse_failure(test_case->input, serialize_handlers,
parser_method, (int)i);
}
}
}
extern "C" {
int run_tests(int argc, char *argv[]) {
UPB_UNUSED(argc);
UPB_UNUSED(argv);
test_json_roundtrip();
test_json_failure();
return 0;
}
}

File diff suppressed because it is too large Load Diff

@ -1,128 +0,0 @@
syntax = "proto2";
enum TestEnum {
FOO = 1;
}
message Empty {}
message DecoderTest {
optional double f_double = 1;
optional float f_float = 2;
optional int64 f_int64 = 3;
optional uint64 f_uint64 = 4;
optional int32 f_int32 = 5;
optional fixed64 f_fixed64 = 6;
optional fixed32 f_fixed32 = 7;
optional bool f_bool = 8;
optional string f_string = 9;
optional DecoderTest f_message = 11;
optional bytes f_bytes = 12;
optional uint32 f_uint32 = 13;
optional TestEnum f_enum = 14;
optional sfixed32 f_sfixed32 = 15;
optional sfixed64 f_sfixed64 = 16;
optional sint32 f_sint32 = 17;
optional sint64 f_sint64 = 18;
optional string nop_field = 40;
repeated double r_double = 536869912;
repeated float r_float = 536869913;
repeated int64 r_int64 = 536869914;
repeated uint64 r_uint64 = 536869915;
repeated int32 r_int32 = 536869916;
repeated fixed64 r_fixed64 = 536869917;
repeated fixed32 r_fixed32 = 536869918;
repeated bool r_bool = 536869919;
repeated string r_string = 536869920;
repeated DecoderTest r_message = 536869922;
repeated bytes r_bytes = 536869923;
repeated uint32 r_uint32 = 536869924;
repeated TestEnum r_enum = 536869925;
repeated sfixed32 r_sfixed32 = 536869926;
repeated sfixed64 r_sfixed64 = 536869927;
repeated sint32 r_sint32 = 536869928;
repeated sint64 r_sint64 = 536869929;
optional group F_group = 10 {
optional double f_double = 1;
optional float f_float = 2;
optional int64 f_int64 = 3;
optional uint64 f_uint64 = 4;
optional int32 f_int32 = 5;
optional fixed64 f_fixed64 = 6;
optional fixed32 f_fixed32 = 7;
optional bool f_bool = 8;
optional string f_string = 9;
optional DecoderTest f_message = 11;
optional bytes f_bytes = 12;
optional uint32 f_uint32 = 13;
optional TestEnum f_enum = 14;
optional sfixed32 f_sfixed32 = 15;
optional sfixed64 f_sfixed64 = 16;
optional sint32 f_sint32 = 17;
optional sint64 f_sint64 = 18;
optional string nop_field = 40;
repeated double r_double = 536869912;
repeated float r_float = 536869913;
repeated int64 r_int64 = 536869914;
repeated uint64 r_uint64 = 536869915;
repeated int32 r_int32 = 536869916;
repeated fixed64 r_fixed64 = 536869917;
repeated fixed32 r_fixed32 = 536869918;
repeated bool r_bool = 536869919;
repeated string r_string = 536869920;
repeated DecoderTest r_message = 536869922;
repeated bytes r_bytes = 536869923;
repeated uint32 r_uint32 = 536869924;
repeated TestEnum r_enum = 536869925;
repeated sfixed32 r_sfixed32 = 536869926;
repeated sfixed64 r_sfixed64 = 536869927;
repeated sint32 r_sint32 = 536869928;
repeated sint64 r_sint64 = 536869929;
}
optional group R_group = 536869921 {
optional double f_double = 1;
optional float f_float = 2;
optional int64 f_int64 = 3;
optional uint64 f_uint64 = 4;
optional int32 f_int32 = 5;
optional fixed64 f_fixed64 = 6;
optional fixed32 f_fixed32 = 7;
optional bool f_bool = 8;
optional string f_string = 9;
optional DecoderTest f_message = 11;
optional bytes f_bytes = 12;
optional uint32 f_uint32 = 13;
optional TestEnum f_enum = 14;
optional sfixed32 f_sfixed32 = 15;
optional sfixed64 f_sfixed64 = 16;
optional sint32 f_sint32 = 17;
optional sint64 f_sint64 = 18;
optional string nop_field = 40;
repeated double r_double = 536869912;
repeated float r_float = 536869913;
repeated int64 r_int64 = 536869914;
repeated uint64 r_uint64 = 536869915;
repeated int32 r_int32 = 536869916;
repeated fixed64 r_fixed64 = 536869917;
repeated fixed32 r_fixed32 = 536869918;
repeated bool r_bool = 536869919;
repeated string r_string = 536869920;
repeated DecoderTest r_message = 536869922;
repeated bytes r_bytes = 536869923;
repeated uint32 r_uint32 = 536869924;
repeated TestEnum r_enum = 536869925;
repeated sfixed32 r_sfixed32 = 536869926;
repeated sfixed64 r_sfixed64 = 536869927;
repeated sint32 r_sint32 = 536869928;
repeated sint64 r_sint64 = 536869929;
}
}

@ -1,102 +0,0 @@
#include <iostream>
#include "google/protobuf/descriptor.upb.h"
#include "google/protobuf/descriptor.upbdefs.h"
#include "tests/test_util.h"
#include "tests/upb_test.h"
#include "upb/pb/decoder.h"
#include "upb/pb/encoder.h"
#include "upb/port_def.inc"
#include "upb/upb.hpp"
template <class T>
class FillStringHandler {
public:
static void SetHandler(upb_byteshandler* handler) {
upb_byteshandler_setstartstr(handler, &FillStringHandler::StartString,
NULL);
upb_byteshandler_setstring(handler, &FillStringHandler::StringBuf, NULL);
}
private:
// TODO(haberman): add UpbBind/UpbMakeHandler support to BytesHandler so these
// can be prettier callbacks.
static void* StartString(void *c, const void *hd, size_t size) {
UPB_UNUSED(hd);
UPB_UNUSED(size);
T* str = static_cast<T*>(c);
str->clear();
return c;
}
static size_t StringBuf(void* c, const void* hd, const char* buf, size_t n,
const upb_bufhandle* h) {
UPB_UNUSED(hd);
UPB_UNUSED(h);
T* str = static_cast<T*>(c);
try {
str->append(buf, n);
return n;
} catch (const std::exception&) {
return 0;
}
}
};
class StringSink {
public:
template <class T>
explicit StringSink(T* target) {
// TODO(haberman): we need to avoid rebuilding a new handler every time,
// but with class globals disallowed for google3 C++ this is tricky.
upb_byteshandler_init(&handler_);
FillStringHandler<T>::SetHandler(&handler_);
input_.Reset(&handler_, target);
}
upb::BytesSink input() { return input_; }
private:
upb_byteshandler handler_;
upb::BytesSink input_;
};
void test_pb_roundtrip() {
std::string input(
google_protobuf_descriptor_proto_upbdefinit.descriptor.data,
google_protobuf_descriptor_proto_upbdefinit.descriptor.size);
std::cout << input.size() << "\n";
upb::SymbolTable symtab;
upb::HandlerCache encoder_cache(upb::pb::EncoderPtr::NewCache());
upb::pb::CodeCache decoder_cache(&encoder_cache);
upb::Arena arena;
upb::Status status;
upb::MessageDefPtr md(
google_protobuf_FileDescriptorProto_getmsgdef(symtab.ptr()));
ASSERT(md);
const upb::Handlers *encoder_handlers = encoder_cache.Get(md);
ASSERT(encoder_handlers);
const upb::pb::DecoderMethodPtr method = decoder_cache.Get(md);
std::string output;
StringSink string_sink(&output);
upb::pb::EncoderPtr encoder =
upb::pb::EncoderPtr::Create(&arena, encoder_handlers, string_sink.input());
upb::pb::DecoderPtr decoder =
upb::pb::DecoderPtr::Create(&arena, method, encoder.input(), &status);
bool ok = upb::PutBuffer(input, decoder.input());
ASSERT(ok);
ASSERT(input == output);
}
extern "C" {
int run_tests(int argc, char *argv[]) {
UPB_UNUSED(argc);
UPB_UNUSED(argv);
test_pb_roundtrip();
return 0;
}
}

@ -14,887 +14,11 @@
#include "tests/test_cpp.upbdefs.h"
#include "tests/upb_test.h"
#include "upb/def.h"
#include "upb/handlers.h"
#include "upb/pb/decoder.h"
#include "upb/pb/textprinter.h"
#include "upb/port_def.inc"
#include "upb/def.hpp"
#include "upb/upb.h"
template <class T>
void AssertInsert(T* const container, const typename T::value_type& val) {
bool inserted = container->insert(val).second;
ASSERT(inserted);
}
//
// Tests for registering and calling handlers in all their variants.
// This test code is very repetitive because we have to declare each
// handler function variant separately, and they all have different
// signatures so it does not lend itself well to templates.
//
// We test three handler types:
// StartMessage (no data params)
// Int32 (1 data param (int32_t))
// String Buf (2 data params (const char*, size_t))
//
// For each handler type we test all 8 handler variants:
// (handler data?) x (function/method) x (returns {void, success})
//
// The one notable thing we don't test at the moment is
// StartSequence/StartString handlers: these are different from StartMessage()
// in that they return void* for the sub-closure. But this is exercised in
// other tests.
//
static const int kExpectedHandlerData = 1232323;
class StringBufTesterBase {
public:
static constexpr int kFieldNumber = 3;
StringBufTesterBase() : seen_(false), handler_data_val_(0) {}
void CallAndVerify(upb::Sink sink, upb::FieldDefPtr f) {
upb_selector_t start;
ASSERT(upb_handlers_getselector(f.ptr(), UPB_HANDLER_STARTSTR, &start));
upb_selector_t str;
ASSERT(upb_handlers_getselector(f.ptr(), UPB_HANDLER_STRING, &str));
ASSERT(!seen_);
upb::Sink sub;
sink.StartMessage();
sink.StartString(start, 0, &sub);
size_t ret = sub.PutStringBuffer(str, &buf_, 5, &handle_);
ASSERT(seen_);
ASSERT(len_ == 5);
ASSERT(ret == 5);
ASSERT(handler_data_val_ == kExpectedHandlerData);
}
protected:
bool seen_;
int handler_data_val_;
size_t len_;
char buf_;
upb_bufhandle handle_;
};
// Test 8 combinations of:
// (handler data?) x (buffer handle?) x (function/method)
//
// Then we add one test each for this variation: to prevent combinatorial
// explosion of these tests we don't test the full 16 combinations, but
// rely on our knowledge that the implementation processes the return wrapping
// in a second separate and independent stage:
//
// (function/method)
class StringBufTesterVoidMethodNoHandlerDataNoHandle
: public StringBufTesterBase {
public:
typedef StringBufTesterVoidMethodNoHandlerDataNoHandle ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStringHandler(f, UpbMakeHandler(&ME::Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
void Handler(const char *buf, size_t len) {
ASSERT(buf == &buf_);
seen_ = true;
len_ = len;
}
};
class StringBufTesterVoidMethodNoHandlerDataWithHandle
: public StringBufTesterBase {
public:
typedef StringBufTesterVoidMethodNoHandlerDataWithHandle ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStringHandler(f, UpbMakeHandler(&ME::Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
void Handler(const char *buf, size_t len, const upb_bufhandle* handle) {
ASSERT(buf == &buf_);
ASSERT(handle == &handle_);
seen_ = true;
len_ = len;
}
};
class StringBufTesterVoidMethodWithHandlerDataNoHandle
: public StringBufTesterBase {
public:
typedef StringBufTesterVoidMethodWithHandlerDataNoHandle ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStringHandler(
f, UpbBind(&ME::Handler, new int(kExpectedHandlerData))));
}
private:
void Handler(const int* hd, const char *buf, size_t len) {
ASSERT(buf == &buf_);
handler_data_val_ = *hd;
seen_ = true;
len_ = len;
}
};
class StringBufTesterVoidMethodWithHandlerDataWithHandle
: public StringBufTesterBase {
public:
typedef StringBufTesterVoidMethodWithHandlerDataWithHandle ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStringHandler(
f, UpbBind(&ME::Handler, new int(kExpectedHandlerData))));
}
private:
void Handler(const int* hd, const char* buf, size_t len,
const upb_bufhandle* handle) {
ASSERT(buf == &buf_);
ASSERT(handle == &handle_);
handler_data_val_ = *hd;
seen_ = true;
len_ = len;
}
};
class StringBufTesterVoidFunctionNoHandlerDataNoHandle
: public StringBufTesterBase {
public:
typedef StringBufTesterVoidFunctionNoHandlerDataNoHandle ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStringHandler(f, UpbMakeHandler(&ME::Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
static void Handler(ME* t, const char *buf, size_t len) {
ASSERT(buf == &t->buf_);
t->seen_ = true;
t->len_ = len;
}
};
class StringBufTesterVoidFunctionNoHandlerDataWithHandle
: public StringBufTesterBase {
public:
typedef StringBufTesterVoidFunctionNoHandlerDataWithHandle ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStringHandler(f, UpbMakeHandler(&ME::Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
static void Handler(ME* t, const char* buf, size_t len,
const upb_bufhandle* handle) {
ASSERT(buf == &t->buf_);
ASSERT(handle == &t->handle_);
t->seen_ = true;
t->len_ = len;
}
};
class StringBufTesterVoidFunctionWithHandlerDataNoHandle
: public StringBufTesterBase {
public:
typedef StringBufTesterVoidFunctionWithHandlerDataNoHandle ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStringHandler(
f, UpbBind(&ME::Handler, new int(kExpectedHandlerData))));
}
private:
static void Handler(ME* t, const int* hd, const char *buf, size_t len) {
ASSERT(buf == &t->buf_);
t->handler_data_val_ = *hd;
t->seen_ = true;
t->len_ = len;
}
};
class StringBufTesterVoidFunctionWithHandlerDataWithHandle
: public StringBufTesterBase {
public:
typedef StringBufTesterVoidFunctionWithHandlerDataWithHandle ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStringHandler(
f, UpbBind(&ME::Handler, new int(kExpectedHandlerData))));
}
private:
static void Handler(ME* t, const int* hd, const char* buf, size_t len,
const upb_bufhandle* handle) {
ASSERT(buf == &t->buf_);
ASSERT(handle == &t->handle_);
t->handler_data_val_ = *hd;
t->seen_ = true;
t->len_ = len;
}
};
class StringBufTesterSizeTMethodNoHandlerDataNoHandle
: public StringBufTesterBase {
public:
typedef StringBufTesterSizeTMethodNoHandlerDataNoHandle ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStringHandler(f, UpbMakeHandler(&ME::Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
size_t Handler(const char *buf, size_t len) {
ASSERT(buf == &buf_);
seen_ = true;
len_ = len;
return len;
}
};
class StringBufTesterBoolMethodNoHandlerDataNoHandle
: public StringBufTesterBase {
public:
typedef StringBufTesterBoolMethodNoHandlerDataNoHandle ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStringHandler(f, UpbMakeHandler(&ME::Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
bool Handler(const char *buf, size_t len) {
ASSERT(buf == &buf_);
seen_ = true;
len_ = len;
return true;
}
};
class StartMsgTesterBase {
public:
// We don't need the FieldDef it will create, but the test harness still
// requires that we provide one.
static constexpr int kFieldNumber = 3;
StartMsgTesterBase() : seen_(false), handler_data_val_(0) {}
void CallAndVerify(upb::Sink sink, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(!seen_);
sink.StartMessage();
ASSERT(seen_);
ASSERT(handler_data_val_ == kExpectedHandlerData);
}
protected:
bool seen_;
int handler_data_val_;
};
// Test all 8 combinations of:
// (handler data?) x (function/method) x (returns {void, bool})
class StartMsgTesterVoidFunctionNoHandlerData : public StartMsgTesterBase {
public:
typedef StartMsgTesterVoidFunctionNoHandlerData ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStartMessageHandler(UpbMakeHandler(&Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
//static void Handler(ME* t) {
static void Handler(ME* t) {
t->seen_ = true;
}
};
class StartMsgTesterBoolFunctionNoHandlerData : public StartMsgTesterBase {
public:
typedef StartMsgTesterBoolFunctionNoHandlerData ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStartMessageHandler(UpbMakeHandler(&Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
static bool Handler(ME* t) {
t->seen_ = true;
return true;
}
};
class StartMsgTesterVoidMethodNoHandlerData : public StartMsgTesterBase {
public:
typedef StartMsgTesterVoidMethodNoHandlerData ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStartMessageHandler(UpbMakeHandler(&ME::Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
void Handler() {
seen_ = true;
}
};
class StartMsgTesterBoolMethodNoHandlerData : public StartMsgTesterBase {
public:
typedef StartMsgTesterBoolMethodNoHandlerData ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStartMessageHandler(UpbMakeHandler(&ME::Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
bool Handler() {
seen_ = true;
return true;
}
};
class StartMsgTesterVoidFunctionWithHandlerData : public StartMsgTesterBase {
public:
typedef StartMsgTesterVoidFunctionWithHandlerData ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStartMessageHandler(
UpbBind(&Handler, new int(kExpectedHandlerData))));
}
private:
static void Handler(ME* t, const int* hd) {
t->handler_data_val_ = *hd;
t->seen_ = true;
}
};
class StartMsgTesterBoolFunctionWithHandlerData : public StartMsgTesterBase {
public:
typedef StartMsgTesterBoolFunctionWithHandlerData ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStartMessageHandler(
UpbBind(&Handler, new int(kExpectedHandlerData))));
}
private:
static bool Handler(ME* t, const int* hd) {
t->handler_data_val_ = *hd;
t->seen_ = true;
return true;
}
};
class StartMsgTesterVoidMethodWithHandlerData : public StartMsgTesterBase {
public:
typedef StartMsgTesterVoidMethodWithHandlerData ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStartMessageHandler(
UpbBind(&ME::Handler, new int(kExpectedHandlerData))));
}
private:
void Handler(const int* hd) {
handler_data_val_ = *hd;
seen_ = true;
}
};
class StartMsgTesterBoolMethodWithHandlerData : public StartMsgTesterBase {
public:
typedef StartMsgTesterBoolMethodWithHandlerData ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
UPB_UNUSED(f);
ASSERT(h.SetStartMessageHandler(
UpbBind(&ME::Handler, new int(kExpectedHandlerData))));
}
private:
bool Handler(const int* hd) {
handler_data_val_ = *hd;
seen_ = true;
return true;
}
};
class Int32ValueTesterBase {
public:
static constexpr int kFieldNumber = 1;
Int32ValueTesterBase() : seen_(false), val_(0), handler_data_val_(0) {}
void CallAndVerify(upb::Sink sink, upb::FieldDefPtr f) {
upb_selector_t s;
ASSERT(upb_handlers_getselector(f.ptr(), UPB_HANDLER_INT32, &s));
ASSERT(!seen_);
sink.PutInt32(s, 5);
ASSERT(seen_);
ASSERT(handler_data_val_ == kExpectedHandlerData);
ASSERT(val_ == 5);
}
protected:
bool seen_;
int32_t val_;
int handler_data_val_;
};
// Test all 8 combinations of:
// (handler data?) x (function/method) x (returns {void, bool})
class ValueTesterInt32VoidFunctionNoHandlerData
: public Int32ValueTesterBase {
public:
typedef ValueTesterInt32VoidFunctionNoHandlerData ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
ASSERT(h.SetInt32Handler(f, UpbMakeHandler(&Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
static void Handler(ME* t, int32_t val) {
t->val_ = val;
t->seen_ = true;
}
};
class ValueTesterInt32BoolFunctionNoHandlerData
: public Int32ValueTesterBase {
public:
typedef ValueTesterInt32BoolFunctionNoHandlerData ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
ASSERT(h.SetInt32Handler(f, UpbMakeHandler(&Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
static bool Handler(ME* t, int32_t val) {
t->val_ = val;
t->seen_ = true;
return true;
}
};
class ValueTesterInt32VoidMethodNoHandlerData : public Int32ValueTesterBase {
public:
typedef ValueTesterInt32VoidMethodNoHandlerData ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
ASSERT(h.SetInt32Handler(f, UpbMakeHandler(&ME::Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
void Handler(int32_t val) {
val_ = val;
seen_ = true;
}
};
class ValueTesterInt32BoolMethodNoHandlerData : public Int32ValueTesterBase {
public:
typedef ValueTesterInt32BoolMethodNoHandlerData ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
ASSERT(h.SetInt32Handler(f, UpbMakeHandler(&ME::Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
bool Handler(int32_t val) {
val_ = val;
seen_ = true;
return true;
}
};
class ValueTesterInt32VoidFunctionWithHandlerData
: public Int32ValueTesterBase {
public:
typedef ValueTesterInt32VoidFunctionWithHandlerData ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
ASSERT(h.SetInt32Handler(
f, UpbBind(&Handler, new int(kExpectedHandlerData))));
}
private:
static void Handler(ME* t, const int* hd, int32_t val) {
t->val_ = val;
t->handler_data_val_ = *hd;
t->seen_ = true;
}
};
class ValueTesterInt32BoolFunctionWithHandlerData
: public Int32ValueTesterBase {
public:
typedef ValueTesterInt32BoolFunctionWithHandlerData ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
ASSERT(h.SetInt32Handler(
f, UpbBind(&Handler, new int(kExpectedHandlerData))));
}
private:
static bool Handler(ME* t, const int* hd, int32_t val) {
t->val_ = val;
t->handler_data_val_ = *hd;
t->seen_ = true;
return true;
}
};
class ValueTesterInt32VoidMethodWithHandlerData : public Int32ValueTesterBase {
public:
typedef ValueTesterInt32VoidMethodWithHandlerData ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
ASSERT(h.SetInt32Handler(
f, UpbBind(&ME::Handler, new int(kExpectedHandlerData))));
}
private:
void Handler(const int* hd, int32_t val) {
val_ = val;
handler_data_val_ = *hd;
seen_ = true;
}
};
class ValueTesterInt32BoolMethodWithHandlerData : public Int32ValueTesterBase {
public:
typedef ValueTesterInt32BoolMethodWithHandlerData ME;
void Register(upb::HandlersPtr h, upb::FieldDefPtr f) {
ASSERT(h.SetInt32Handler(
f, UpbBind(&ME::Handler, new int(kExpectedHandlerData))));
}
private:
bool Handler(const int* hd, int32_t val) {
val_ = val;
handler_data_val_ = *hd;
seen_ = true;
return true;
}
};
template <class T>
void RegisterHandlers(const void* closure, upb::Handlers* h_ptr) {
T* tester = const_cast<T*>(static_cast<const T*>(closure));
upb::HandlersPtr h(h_ptr);
upb::FieldDefPtr f = h.message_def().FindFieldByNumber(T::kFieldNumber);
ASSERT(f);
tester->Register(h, f);
}
template <class T>
void TestHandler() {
T tester;
upb::SymbolTable symtab;
upb::HandlerCache cache(&RegisterHandlers<T>, &tester);
upb::MessageDefPtr md(upb_test_TestMessage_getmsgdef(symtab.ptr()));
ASSERT(md);
upb::FieldDefPtr f = md.FindFieldByNumber(T::kFieldNumber);
ASSERT(f);
const upb::Handlers* h = cache.Get(md);
upb::Sink sink(h, &tester);
tester.CallAndVerify(sink, f);
}
class T1 {};
class T2 {};
template <class C>
void DoNothingHandler(C* closure) {
UPB_UNUSED(closure);
}
template <class C>
void DoNothingInt32Handler(C* closure, int32_t val) {
UPB_UNUSED(closure);
UPB_UNUSED(val);
}
template <class R>
class DoNothingStartHandler {
public:
// We wrap these functions inside of a class for a somewhat annoying reason.
// UpbMakeHandler() is a macro, so we can't say
// UpbMakeHandler(DoNothingStartHandler<T1, T2>)
//
// because otherwise the preprocessor gets confused at the comma and tries to
// make it two macro arguments. The usual solution doesn't work either:
// UpbMakeHandler((DoNothingStartHandler<T1, T2>))
//
// If we do that the macro expands correctly, but then it tries to pass that
// parenthesized expression as a template parameter, ie. Type<(F)>, which
// isn't legal C++ (Clang will compile it but complains with
// warning: address non-type template argument cannot be surrounded by
// parentheses
//
// This two-level thing allows us to effectively pass two template parameters,
// but without any commas:
// UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T2>)
template <class C>
static R* Handler(C* closure) {
UPB_UNUSED(closure);
return NULL;
}
template <class C>
static R* String(C* closure, size_t size_len) {
UPB_UNUSED(closure);
UPB_UNUSED(size_len);
return NULL;
}
};
template <class C>
void DoNothingStringBufHandler(C* closure, const char *buf, size_t len) {
UPB_UNUSED(closure);
UPB_UNUSED(buf);
UPB_UNUSED(len);
}
template <class C>
void DoNothingEndMessageHandler(C* closure, upb_status *status) {
UPB_UNUSED(closure);
UPB_UNUSED(status);
}
void RegisterMismatchedTypes(const void* closure, upb::Handlers* h_ptr) {
upb::HandlersPtr h(h_ptr);
UPB_UNUSED(closure);
upb::MessageDefPtr md(h.message_def());
ASSERT(md);
upb::FieldDefPtr i32 = md.FindFieldByName("i32");
upb::FieldDefPtr r_i32 = md.FindFieldByName("r_i32");
upb::FieldDefPtr str = md.FindFieldByName("str");
upb::FieldDefPtr r_str = md.FindFieldByName("r_str");
upb::FieldDefPtr msg = md.FindFieldByName("msg");
upb::FieldDefPtr r_msg = md.FindFieldByName("r_msg");
ASSERT(i32);
ASSERT(r_i32);
ASSERT(str);
ASSERT(r_str);
ASSERT(msg);
ASSERT(r_msg);
// Establish T1 as the top-level closure type.
ASSERT(h.SetInt32Handler(i32, UpbMakeHandler(DoNothingInt32Handler<T1>)));
// Now any other attempt to set another handler with T2 as the top-level
// closure should fail. But setting these same handlers with T1 as the
// top-level closure will succeed.
ASSERT(!h.SetStartMessageHandler(UpbMakeHandler(DoNothingHandler<T2>)));
ASSERT(h.SetStartMessageHandler(UpbMakeHandler(DoNothingHandler<T1>)));
ASSERT(
!h.SetEndMessageHandler(UpbMakeHandler(DoNothingEndMessageHandler<T2>)));
ASSERT(
h.SetEndMessageHandler(UpbMakeHandler(DoNothingEndMessageHandler<T1>)));
ASSERT(!h.SetStartStringHandler(
str, UpbMakeHandler(DoNothingStartHandler<T1>::String<T2>)));
ASSERT(h.SetStartStringHandler(
str, UpbMakeHandler(DoNothingStartHandler<T1>::String<T1>)));
ASSERT(!h.SetEndStringHandler(str, UpbMakeHandler(DoNothingHandler<T2>)));
ASSERT(h.SetEndStringHandler(str, UpbMakeHandler(DoNothingHandler<T1>)));
ASSERT(!h.SetStartSubMessageHandler(
msg, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T2>)));
ASSERT(h.SetStartSubMessageHandler(
msg, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T1>)));
ASSERT(
!h.SetEndSubMessageHandler(msg, UpbMakeHandler(DoNothingHandler<T2>)));
ASSERT(
h.SetEndSubMessageHandler(msg, UpbMakeHandler(DoNothingHandler<T1>)));
ASSERT(!h.SetStartSequenceHandler(
r_i32, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T2>)));
ASSERT(h.SetStartSequenceHandler(
r_i32, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T1>)));
ASSERT(!h.SetEndSequenceHandler(
r_i32, UpbMakeHandler(DoNothingHandler<T2>)));
ASSERT(h.SetEndSequenceHandler(
r_i32, UpbMakeHandler(DoNothingHandler<T1>)));
ASSERT(!h.SetStartSequenceHandler(
r_msg, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T2>)));
ASSERT(h.SetStartSequenceHandler(
r_msg, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T1>)));
ASSERT(!h.SetEndSequenceHandler(
r_msg, UpbMakeHandler(DoNothingHandler<T2>)));
ASSERT(h.SetEndSequenceHandler(
r_msg, UpbMakeHandler(DoNothingHandler<T1>)));
ASSERT(!h.SetStartSequenceHandler(
r_str, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T2>)));
ASSERT(h.SetStartSequenceHandler(
r_str, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T1>)));
ASSERT(!h.SetEndSequenceHandler(
r_str, UpbMakeHandler(DoNothingHandler<T2>)));
ASSERT(h.SetEndSequenceHandler(
r_str, UpbMakeHandler(DoNothingHandler<T1>)));
// By setting T1 as the return type for the Start* handlers we have
// established T1 as the type of the sequence and string frames.
// Setting callbacks that use T2 should fail, but T1 should succeed.
ASSERT(
!h.SetStringHandler(str, UpbMakeHandler(DoNothingStringBufHandler<T2>)));
ASSERT(
h.SetStringHandler(str, UpbMakeHandler(DoNothingStringBufHandler<T1>)));
ASSERT(!h.SetInt32Handler(r_i32, UpbMakeHandler(DoNothingInt32Handler<T2>)));
ASSERT(h.SetInt32Handler(r_i32, UpbMakeHandler(DoNothingInt32Handler<T1>)));
ASSERT(!h.SetStartSubMessageHandler(
r_msg, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T2>)));
ASSERT(h.SetStartSubMessageHandler(
r_msg, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T1>)));
ASSERT(!h.SetEndSubMessageHandler(r_msg,
UpbMakeHandler(DoNothingHandler<T2>)));
ASSERT(h.SetEndSubMessageHandler(r_msg,
UpbMakeHandler(DoNothingHandler<T1>)));
ASSERT(!h.SetStartStringHandler(
r_str, UpbMakeHandler(DoNothingStartHandler<T1>::String<T2>)));
ASSERT(h.SetStartStringHandler(
r_str, UpbMakeHandler(DoNothingStartHandler<T1>::String<T1>)));
ASSERT(
!h.SetEndStringHandler(r_str, UpbMakeHandler(DoNothingHandler<T2>)));
ASSERT(h.SetEndStringHandler(r_str, UpbMakeHandler(DoNothingHandler<T1>)));
ASSERT(!h.SetStringHandler(r_str,
UpbMakeHandler(DoNothingStringBufHandler<T2>)));
ASSERT(h.SetStringHandler(r_str,
UpbMakeHandler(DoNothingStringBufHandler<T1>)));
}
void RegisterMismatchedTypes2(const void* closure, upb::Handlers* h_ptr) {
upb::HandlersPtr h(h_ptr);
UPB_UNUSED(closure);
upb::MessageDefPtr md(h.message_def());
ASSERT(md);
upb::FieldDefPtr i32 = md.FindFieldByName("i32");
upb::FieldDefPtr r_i32 = md.FindFieldByName("r_i32");
upb::FieldDefPtr str = md.FindFieldByName("str");
upb::FieldDefPtr r_str = md.FindFieldByName("r_str");
upb::FieldDefPtr msg = md.FindFieldByName("msg");
upb::FieldDefPtr r_msg = md.FindFieldByName("r_msg");
ASSERT(i32);
ASSERT(r_i32);
ASSERT(str);
ASSERT(r_str);
ASSERT(msg);
ASSERT(r_msg);
// For our second test we do the same in reverse. We directly set the type of
// the frame and then observe failures at registering a Start* handler that
// returns a different type.
// First establish the type of a sequence frame directly.
ASSERT(h.SetInt32Handler(r_i32, UpbMakeHandler(DoNothingInt32Handler<T1>)));
// Now setting a StartSequence callback that returns a different type should
// fail.
ASSERT(!h.SetStartSequenceHandler(
r_i32, UpbMakeHandler(DoNothingStartHandler<T2>::Handler<T1>)));
ASSERT(h.SetStartSequenceHandler(
r_i32, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T1>)));
// Establish a string frame directly.
ASSERT(h.SetStringHandler(r_str,
UpbMakeHandler(DoNothingStringBufHandler<T1>)));
// Fail setting a StartString callback that returns a different type.
ASSERT(!h.SetStartStringHandler(
r_str, UpbMakeHandler(DoNothingStartHandler<T2>::String<T1>)));
ASSERT(h.SetStartStringHandler(
r_str, UpbMakeHandler(DoNothingStartHandler<T1>::String<T1>)));
// The previous established T1 as the frame for the r_str sequence.
ASSERT(!h.SetStartSequenceHandler(
r_str, UpbMakeHandler(DoNothingStartHandler<T2>::Handler<T1>)));
ASSERT(h.SetStartSequenceHandler(
r_str, UpbMakeHandler(DoNothingStartHandler<T1>::Handler<T1>)));
}
void TestMismatchedTypes() {
// First create a schema for our test.
upb::SymbolTable symtab;
upb::HandlerCache handler_cache(&RegisterMismatchedTypes, nullptr);
upb::HandlerCache handler_cache2(&RegisterMismatchedTypes2, nullptr);
const upb::MessageDefPtr md(upb_test_TestMessage_getmsgdef(symtab.ptr()));
// Now test the type-checking in handler registration.
handler_cache.Get(md);
handler_cache2.Get(md);
}
class IntIncrementer {
public:
explicit IntIncrementer(int* x) : x_(x) { (*x_)++; }
~IntIncrementer() { (*x_)--; }
static void Handler(void* closure, const IntIncrementer* incrementer,
int32_t x) {
UPB_UNUSED(closure);
UPB_UNUSED(incrementer);
UPB_UNUSED(x);
}
private:
int* x_;
};
void RegisterIncrementor(const void* closure, upb::Handlers* h_ptr) {
const int* x = static_cast<const int*>(closure);
upb::HandlersPtr h(h_ptr);
upb::FieldDefPtr f = h.message_def().FindFieldByName("i32");
h.SetInt32Handler(f, UpbBind(&IntIncrementer::Handler,
new IntIncrementer(const_cast<int*>(x))));
}
void TestHandlerDataDestruction() {
int x = 0;
{
upb::SymbolTable symtab;
upb::HandlerCache cache(&RegisterIncrementor, &x);
upb::MessageDefPtr md(upb_test_TestMessage_getmsgdef(symtab.ptr()));
cache.Get(md);
ASSERT(x == 1);
}
ASSERT(x == 0);
}
// Must be last.
#include "upb/port_def.inc"
void TestIteration() {
upb::SymbolTable symtab;
@ -977,43 +101,23 @@ void TestInlinedArena() {
ASSERT(n == 0);
}
void TestDefault() {
upb::SymbolTable symtab;
upb::MessageDefPtr md(upb_test_TestMessage_getmsgdef(symtab.ptr()));
upb::FieldDefPtr i32_f = md.FindFieldByName("i32");
upb::FieldDefPtr str_f = md.FindFieldByName("str");
ASSERT(i32_f && str_f);
ASSERT(i32_f.default_value().int32_val == 5);
ASSERT(strcmp(str_f.default_value().str_val.data, "abc") == 0);
ASSERT(str_f.default_value().str_val.size == 3);
}
extern "C" {
int run_tests() {
TestHandler<ValueTesterInt32VoidFunctionNoHandlerData>();
TestHandler<ValueTesterInt32BoolFunctionNoHandlerData>();
TestHandler<ValueTesterInt32VoidMethodNoHandlerData>();
TestHandler<ValueTesterInt32BoolMethodNoHandlerData>();
TestHandler<ValueTesterInt32VoidFunctionWithHandlerData>();
TestHandler<ValueTesterInt32BoolFunctionWithHandlerData>();
TestHandler<ValueTesterInt32VoidMethodWithHandlerData>();
TestHandler<ValueTesterInt32BoolMethodWithHandlerData>();
TestHandler<StartMsgTesterVoidFunctionNoHandlerData>();
TestHandler<StartMsgTesterBoolFunctionNoHandlerData>();
TestHandler<StartMsgTesterVoidMethodNoHandlerData>();
TestHandler<StartMsgTesterBoolMethodNoHandlerData>();
TestHandler<StartMsgTesterVoidFunctionWithHandlerData>();
TestHandler<StartMsgTesterBoolFunctionWithHandlerData>();
TestHandler<StartMsgTesterVoidMethodWithHandlerData>();
TestHandler<StartMsgTesterBoolMethodWithHandlerData>();
TestHandler<StringBufTesterVoidMethodNoHandlerDataNoHandle>();
TestHandler<StringBufTesterVoidMethodNoHandlerDataWithHandle>();
TestHandler<StringBufTesterVoidMethodWithHandlerDataNoHandle>();
TestHandler<StringBufTesterVoidMethodWithHandlerDataWithHandle>();
TestHandler<StringBufTesterVoidFunctionNoHandlerDataNoHandle>();
TestHandler<StringBufTesterVoidFunctionNoHandlerDataWithHandle>();
TestHandler<StringBufTesterVoidFunctionWithHandlerDataNoHandle>();
TestHandler<StringBufTesterVoidFunctionWithHandlerDataWithHandle>();
TestHandler<StringBufTesterSizeTMethodNoHandlerDataNoHandle>();
TestHandler<StringBufTesterBoolMethodNoHandlerDataNoHandle>();
TestMismatchedTypes();
TestHandlerDataDestruction();
TestIteration();
TestArena();
TestDefault();
return 0;
}

@ -3,9 +3,9 @@ syntax = "proto2";
package upb.test;
message TestMessage {
optional int32 i32 = 1;
optional int32 i32 = 1 [default = 5];
repeated int32 r_i32 = 2;
optional string str = 3;
optional string str = 3 [default = "abc"];
repeated string r_str = 4;
optional TestMessage msg = 5;
repeated TestMessage r_msg = 6;

@ -410,6 +410,73 @@ void test_status_truncation(void) {
}
}
void decrement_int(void *ptr) {
int* iptr = ptr;
(*iptr)--;
}
void test_arena_fuse(void) {
int i1 = 5;
int i2 = 5;
int i3 = 5;
int i4 = 5;
upb_arena *arena1 = upb_arena_new();
upb_arena *arena2 = upb_arena_new();
upb_arena_addcleanup(arena1, &i1, decrement_int);
upb_arena_addcleanup(arena2, &i2, decrement_int);
upb_arena_fuse(arena1, arena2);
upb_arena_addcleanup(arena1, &i3, decrement_int);
upb_arena_addcleanup(arena2, &i4, decrement_int);
upb_arena_free(arena1);
ASSERT(i1 == 5);
ASSERT(i2 == 5);
ASSERT(i3 == 5);
ASSERT(i4 == 5);
upb_arena_free(arena2);
ASSERT(i1 == 4);
ASSERT(i2 == 4);
ASSERT(i3 == 4);
ASSERT(i4 == 4);
}
void test_arena_decode(void) {
// Tests against a bug that previously existed when passing an arena to
// upb_decode().
char large_string[1024] = {0};
upb_strview large_string_view = {large_string, sizeof(large_string)};
upb_arena *tmp = upb_arena_new();
protobuf_test_messages_proto3_TestAllTypesProto3 *msg =
protobuf_test_messages_proto3_TestAllTypesProto3_new(tmp);
protobuf_test_messages_proto3_TestAllTypesProto3_set_optional_bytes(
msg, large_string_view);
upb_strview serialized;
serialized.data = protobuf_test_messages_proto3_TestAllTypesProto3_serialize(
msg, tmp, &serialized.size);
upb_arena *arena = upb_arena_new();
// Parse the large payload, forcing an arena block to be allocated. This used
// to corrupt the cleanup list, preventing subsequent upb_arena_addcleanup()
// calls from working properly.
protobuf_test_messages_proto3_TestAllTypesProto3_parse(
serialized.data, serialized.size, arena);
int i1 = 5;
upb_arena_addcleanup(arena, &i1, decrement_int);
ASSERT(i1 == 5);
upb_arena_free(arena);
ASSERT(i1 == 4);
upb_arena_free(tmp);
}
int run_tests(int argc, char *argv[]) {
test_scalars();
test_utf8();
@ -419,5 +486,7 @@ int run_tests(int argc, char *argv[]) {
test_repeated();
test_null_decode_buf();
test_status_truncation();
test_arena_fuse();
test_arena_decode();
return 0;
}

@ -14,6 +14,7 @@
#include <vector>
#include "tests/upb_test.h"
#include "upb/upb.hpp"
#include "upb/table.int.h"
#include "upb/port_def.inc"
@ -25,12 +26,10 @@ namespace upb {
template <class T> upb_value MakeUpbValue(T val);
template <class T> T GetUpbValue(upb_value val);
template <class T> upb_ctype_t GetUpbValueType();
#define FUNCS(name, type_t, enumval) \
template<> upb_value MakeUpbValue<type_t>(type_t val) { return upb_value_ ## name(val); } \
template<> type_t GetUpbValue<type_t>(upb_value val) { return upb_value_get ## name(val); } \
template<> upb_ctype_t GetUpbValueType<type_t>() { return enumval; }
FUNCS(int32, int32_t, UPB_CTYPE_INT32)
FUNCS(int64, int64_t, UPB_CTYPE_INT64)
@ -46,13 +45,12 @@ FUNCS(fptr, upb_func*, UPB_CTYPE_FPTR)
class IntTable {
public:
IntTable(upb_ctype_t value_type) { upb_inttable_init(&table_, value_type); }
~IntTable() { upb_inttable_uninit(&table_); }
IntTable() { upb_inttable_init(&table_, arena_.ptr()); }
size_t count() { return upb_inttable_count(&table_); }
bool Insert(uintptr_t key, upb_value val) {
return upb_inttable_insert(&table_, key, val);
return upb_inttable_insert(&table_, key, val, arena_.ptr());
}
bool Replace(uintptr_t key, upb_value val) {
@ -73,11 +71,11 @@ class IntTable {
std::pair<bool, upb_value> Lookup32(uint32_t key) const {
std::pair<bool, upb_value> ret;
ret.first = upb_inttable_lookup32(&table_, key, &ret.second);
ret.first = upb_inttable_lookup(&table_, key, &ret.second);
return ret;
}
void Compact() { upb_inttable_compact(&table_); }
void Compact() { upb_inttable_compact(&table_, arena_.ptr()); }
class iterator : public std::iterator<std::forward_iterator_tag,
std::pair<uintptr_t, upb_value> > {
@ -115,24 +113,25 @@ class IntTable {
upb_inttable_iter iter_;
};
upb::Arena arena_;
upb_inttable table_;
};
class StrTable {
public:
StrTable(upb_ctype_t value_type) { upb_strtable_init(&table_, value_type); }
~StrTable() { upb_strtable_uninit(&table_); }
StrTable() { upb_strtable_init(&table_, 4, arena_.ptr()); }
size_t count() { return upb_strtable_count(&table_); }
bool Insert(const std::string& key, upb_value val) {
return upb_strtable_insert2(&table_, key.c_str(), key.size(), val);
return upb_strtable_insert(&table_, key.c_str(), key.size(), val,
arena_.ptr());
}
std::pair<bool, upb_value> Remove(const std::string& key) {
std::pair<bool, upb_value> ret;
ret.first =
upb_strtable_remove2(&table_, key.c_str(), key.size(), &ret.second);
upb_strtable_remove(&table_, key.c_str(), key.size(), &ret.second);
return ret;
}
@ -144,7 +143,7 @@ class StrTable {
}
void Resize(size_t size_lg2) {
upb_strtable_resize(&table_, size_lg2, &upb_alloc_global);
upb_strtable_resize(&table_, size_lg2, arena_.ptr());
}
class iterator : public std::iterator<std::forward_iterator_tag,
@ -184,13 +183,12 @@ class StrTable {
upb_strtable_iter iter_;
};
upb::Arena arena_;
upb_strtable table_;
};
template <class T> class TypedStrTable {
public:
TypedStrTable() : table_(GetUpbValueType<T>()) {}
size_t count() { return table_.count(); }
bool Insert(const std::string &key, T val) {
@ -260,8 +258,6 @@ template <class T> class TypedStrTable {
template <class T> class TypedIntTable {
public:
TypedIntTable() : table_(GetUpbValueType<T>()) {}
size_t count() { return table_.count(); }
bool Insert(uintptr_t key, T val) {
@ -507,7 +503,7 @@ void test_inttable(int32_t *keys, uint16_t num_entries, const char *desc) {
MAYBE_BREAK;
int32_t key = keys[i & mask];
upb_value v;
bool ok = upb_inttable_lookup32(&table.table_.table_, key, &v);
bool ok = upb_inttable_lookup(&table.table_.table_, key, &v);
x += (uintptr_t)ok;
}
double total = get_usertime() - before;
@ -521,7 +517,7 @@ void test_inttable(int32_t *keys, uint16_t num_entries, const char *desc) {
MAYBE_BREAK;
int32_t key = keys[rand_order[i & mask]];
upb_value v;
bool ok = upb_inttable_lookup32(&table.table_.table_, key, &v);
bool ok = upb_inttable_lookup(&table.table_.table_, key, &v);
x += (uintptr_t)ok;
}
total = get_usertime() - before;
@ -599,12 +595,13 @@ int32_t *get_contiguous_keys(int32_t num) {
}
void test_delete() {
upb::Arena arena;
upb_inttable t;
upb_inttable_init(&t, UPB_CTYPE_BOOL);
upb_inttable_insert(&t, 0, upb_value_bool(true));
upb_inttable_insert(&t, 2, upb_value_bool(true));
upb_inttable_insert(&t, 4, upb_value_bool(true));
upb_inttable_compact(&t);
upb_inttable_init(&t, arena.ptr());
upb_inttable_insert(&t, 0, upb_value_bool(true), arena.ptr());
upb_inttable_insert(&t, 2, upb_value_bool(true), arena.ptr());
upb_inttable_insert(&t, 4, upb_value_bool(true), arena.ptr());
upb_inttable_compact(&t, arena.ptr());
upb_inttable_remove(&t, 0, NULL);
upb_inttable_remove(&t, 2, NULL);
upb_inttable_remove(&t, 4, NULL);
@ -614,17 +611,15 @@ void test_delete() {
upb_inttable_next(&iter)) {
ASSERT(false);
}
upb_inttable_uninit(&t);
}
void test_init() {
for (int i = 0; i < 2048; i++) {
/* Tests that the size calculations in init() (lg2 size for target load)
* work for all expected sizes. */
upb::Arena arena;
upb_strtable t;
upb_strtable_init2(&t, UPB_CTYPE_BOOL, i, &upb_alloc_global);
upb_strtable_uninit(&t);
upb_strtable_init(&t, i, arena.ptr());
}
}

@ -19,6 +19,7 @@ cc_library(
copts = UPB_DEFAULT_COPTS,
visibility = ["//visibility:public"],
deps = [
"//:json",
"//:reflection",
"//:textformat",
"//:upb",

@ -53,12 +53,12 @@ static void lupb_wrapper_pushwrapper(lua_State *L, int narg, const void *def,
/* lupb_msgdef_pushsubmsgdef()
*
* Pops the msgdef wrapper at the top of the stack and replaces it with a msgdef
* wrapper for field |f| of this msgdef.
* wrapper for field |f| of this msgdef (submsg may not be direct, for example it
* may be the submessage of the map value).
*/
void lupb_msgdef_pushsubmsgdef(lua_State *L, const upb_fielddef *f) {
const upb_msgdef *m = upb_fielddef_msgsubdef(f);
assert(m);
assert(upb_fielddef_containingtype(f) == lupb_msgdef_check(L, -1));
lupb_wrapper_pushwrapper(L, -1, m, LUPB_MSGDEF);
lua_replace(L, -2); /* Replace msgdef with submsgdef. */
}
@ -337,6 +337,26 @@ static int lupb_msgdef_oneofcount(lua_State *L) {
return 1;
}
static bool lupb_msgdef_pushnested(lua_State *L, int msgdef, int name) {
const upb_msgdef *m = lupb_msgdef_check(L, msgdef);
lupb_wrapper_pushsymtab(L, msgdef);
upb_symtab *symtab = lupb_symtab_check(L, -1);
lua_pop(L, 1);
/* Construct full package.Message.SubMessage name. */
lua_pushstring(L, upb_msgdef_fullname(m));
lua_pushstring(L, ".");
lua_pushvalue(L, name);
lua_concat(L, 3);
const char *nested_name = lua_tostring(L, -1);
/* Try lookup. */
const upb_msgdef *nested = upb_symtab_lookupmsg(symtab, nested_name);
if (!nested) return false;
lupb_wrapper_pushwrapper(L, msgdef, nested, LUPB_MSGDEF);
return true;
}
/* lupb_msgdef_field()
*
* Handles:
@ -430,6 +450,13 @@ static int lupb_msgdef_fullname(lua_State *L) {
return 1;
}
static int lupb_msgdef_index(lua_State *L) {
if (!lupb_msgdef_pushnested(L, 1, 2)) {
luaL_error(L, "No such nested message");
}
return 1;
}
static int lupb_msgoneofiter_next(lua_State *L) {
const upb_msgdef *m = lupb_msgdef_check(L, lua_upvalueindex(1));
int *index = lua_touserdata(L, lua_upvalueindex(2));
@ -470,7 +497,8 @@ static int lupb_msgdef_tostring(lua_State *L) {
}
static const struct luaL_Reg lupb_msgdef_mm[] = {
{"__call", lupb_msg_pushnew},
{"__call", lupb_msgdef_call},
{"__index", lupb_msgdef_index},
{"__len", lupb_msgdef_fieldcount},
{"__tostring", lupb_msgdef_tostring},
{NULL, NULL}
@ -640,6 +668,13 @@ static int lupb_filedef_package(lua_State *L) {
return 1;
}
static int lupb_filedef_symtab(lua_State *L) {
const upb_filedef *f = lupb_filedef_check(L, 1);
const upb_symtab *symtab = upb_filedef_symtab(f);
lupb_wrapper_pushwrapper(L, 1, symtab, LUPB_SYMTAB);
return 1;
}
static int lupb_filedef_syntax(lua_State *L) {
const upb_filedef *f = lupb_filedef_check(L, 1);
lua_pushnumber(L, upb_filedef_syntax(f));
@ -655,6 +690,7 @@ static const struct luaL_Reg lupb_filedef_m[] = {
{"msgcount", lupb_filedef_msgcount},
{"name", lupb_filedef_name},
{"package", lupb_filedef_package},
{"symtab", lupb_filedef_symtab},
{"syntax", lupb_filedef_syntax},
{NULL, NULL}
};
@ -733,6 +769,10 @@ static int lupb_symtab_new(lua_State *L) {
lua_setfield(L, -2, "__mode");
lua_setmetatable(L, -2);
/* Put the symtab itself in the cache metatable. */
lua_pushvalue(L, -2);
lua_rawsetp(L, -2, lsymtab->symtab);
/* Set the cache as our userval. */
lua_setiuservalue(L, -2, LUPB_CACHE_INDEX);

@ -12,11 +12,12 @@
#include "lauxlib.h"
#include "upb/bindings/lua/upb.h"
#include "upb/json_decode.h"
#include "upb/json_encode.h"
#include "upb/port_def.inc"
#include "upb/reflection.h"
#include "upb/text_encode.h"
#include "upb/port_def.inc"
/*
* Message/Map/Array objects. These objects form a directed graph: a message
* can contain submessages, arrays, and maps, which can then point to other
@ -187,6 +188,13 @@ static void lupb_arena_fuse(lua_State *L, int to, int from) {
upb_arena_fuse(to_arena, from_arena);
}
static void lupb_arena_fuseobjs(lua_State *L, int to, int from) {
lua_getiuservalue(L, to, LUPB_ARENA_INDEX);
lua_getiuservalue(L, from, LUPB_ARENA_INDEX);
lupb_arena_fuse(L, lua_absindex(L, -2), lua_absindex(L, -1));
lua_pop(L, 2);
}
static int lupb_arena_gc(lua_State *L) {
upb_arena *a = lupb_arena_check(L, 1);
upb_arena_free(a);
@ -398,6 +406,10 @@ static int lupb_array_newindex(lua_State *L) {
upb_array_set(larray->arr, n, msgval);
}
if (larray->type == UPB_TYPE_MESSAGE) {
lupb_arena_fuseobjs(L, 1, 3);
}
return 0; /* 1 for chained assignments? */
}
@ -535,6 +547,9 @@ static int lupb_map_newindex(lua_State *L) {
} else {
upb_msgval val = lupb_tomsgval(L, lmap->value_type, 3, 1, LUPB_COPY);
upb_map_set(map, key, val, lupb_arenaget(L, 1));
if (lmap->value_type == UPB_TYPE_MESSAGE) {
lupb_arena_fuseobjs(L, 1, 3);
}
}
return 0;
@ -600,24 +615,43 @@ static upb_msg *lupb_msg_check(lua_State *L, int narg) {
return msg->msg;
}
static const upb_fielddef *lupb_msg_checkfield(lua_State *L, int msg,
int field) {
static const upb_msgdef *lupb_msg_getmsgdef(lua_State *L, int msg) {
lua_getiuservalue(L, msg, LUPB_MSGDEF_INDEX);
const upb_msgdef *m = lupb_msgdef_check(L, -1);
lua_pop(L, 1);
return m;
}
static const upb_fielddef *lupb_msg_tofield(lua_State *L, int msg, int field) {
size_t len;
const char *fieldname = luaL_checklstring(L, field, &len);
const upb_msgdef *m;
const upb_fielddef *f;
const upb_msgdef *m = lupb_msg_getmsgdef(L, msg);
return upb_msgdef_ntof(m, fieldname, len);
}
lua_getiuservalue(L, msg, LUPB_MSGDEF_INDEX);
m = lupb_msgdef_check(L, -1);
f = upb_msgdef_ntof(m, fieldname, len);
static const upb_fielddef *lupb_msg_checkfield(lua_State *L, int msg,
int field) {
const upb_fielddef *f = lupb_msg_tofield(L, msg, field);
if (f == NULL) {
luaL_error(L, "no such field '%s'", fieldname);
luaL_error(L, "no such field '%s'", lua_tostring(L, field));
}
lua_pop(L, 1);
return f;
}
upb_msg *lupb_msg_pushnew(lua_State *L, int narg) {
const upb_msgdef *m = lupb_msgdef_check(L, narg);
lupb_msg *lmsg = lupb_newuserdata(L, sizeof(lupb_msg), 2, LUPB_MSG);
upb_arena *arena = lupb_arena_pushnew(L);
lua_setiuservalue(L, -2, LUPB_ARENA_INDEX);
lua_pushvalue(L, 1);
lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX);
lmsg->msg = upb_msg_new(m, arena);
lupb_cacheset(L, lmsg->msg);
return lmsg->msg;
}
/**
* lupb_msg_newmsgwrapper()
*
@ -707,28 +741,19 @@ static void lupb_msg_typechecksubmsg(lua_State *L, int narg, int msgarg,
/* lupb_msg Public API */
/**
* lupb_msg_pushnew
* lupb_msgdef_call
*
* Handles:
* new_msg = MessageClass()
* new_msg = MessageClass{foo = "bar", baz = 3, quux = {foo = 3}}
*/
int lupb_msg_pushnew(lua_State *L) {
int argcount = lua_gettop(L);
const upb_msgdef *m = lupb_msgdef_check(L, 1);
lupb_msg *lmsg = lupb_newuserdata(L, sizeof(lupb_msg), 2, LUPB_MSG);
upb_arena *arena = lupb_arena_pushnew(L);
int lupb_msgdef_call(lua_State *L) {
int arg_count = lua_gettop(L);
lupb_msg_pushnew(L, 1);
lua_setiuservalue(L, -2, LUPB_ARENA_INDEX);
lua_pushvalue(L, 1);
lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX);
lmsg->msg = upb_msg_new(m, arena);
lupb_cacheset(L, lmsg->msg);
if (argcount > 1) {
if (arg_count > 1) {
/* Set initial fields from table. */
int msg = lua_gettop(L);
int msg = arg_count + 1;
lua_pushnil(L);
while (lua_next(L, 2) != 0) {
lua_pushvalue(L, -2); /* now stack is key, val, key */
@ -813,10 +838,7 @@ static int lupb_msg_newindex(lua_State *L) {
}
if (merge_arenas) {
lua_getiuservalue(L, 1, LUPB_ARENA_INDEX);
lua_getiuservalue(L, 3, LUPB_ARENA_INDEX);
lupb_arena_fuse(L, lua_absindex(L, -2), lua_absindex(L, -1));
lua_pop(L, 2);
lupb_arena_fuseobjs(L, 1, 3);
}
upb_msg_set(msg, f, msgval, lupb_arenaget(L, 1));
@ -867,6 +889,19 @@ static const struct luaL_Reg lupb_msg_mm[] = {
/* lupb_msg toplevel **********************************************************/
static int lupb_getoptions(lua_State *L, int narg) {
int options = 0;
if (lua_gettop(L) >= narg) {
size_t len = lua_rawlen(L, narg);
for (size_t i = 1; i <= len; i++) {
lua_rawgeti(L, narg, i);
options |= lupb_checkuint32(L, -1);
lua_pop(L, 1);
}
}
return options;
}
/**
* lupb_decode()
*
@ -878,26 +913,16 @@ static int lupb_decode(lua_State *L) {
const upb_msgdef *m = lupb_msgdef_check(L, 1);
const char *pb = lua_tolstring(L, 2, &len);
const upb_msglayout *layout = upb_msgdef_layout(m);
upb_msg *msg = lupb_msg_pushnew(L, 1);
upb_arena *arena = lupb_arenaget(L, -1);
char *buf;
upb_msg *msg;
upb_arena *arena;
bool ok;
/* Create message. */
lua_pushcfunction(L, &lupb_msg_pushnew);
lua_pushvalue(L, 1);
lua_call(L, 1, 1);
msg = lupb_msg_check(L, -1);
lua_getiuservalue(L, -1, LUPB_ARENA_INDEX);
arena = lupb_arena_check(L, -1);
lua_pop(L, 1);
/* Copy input data to arena, message will reference it. */
buf = upb_arena_malloc(arena, len);
memcpy(buf, pb, len);
ok = upb_decode(buf, len, msg, layout, arena);
ok = _upb_decode(buf, len, msg, layout, arena, UPB_DECODE_ALIAS);
if (!ok) {
lua_pushstring(L, "Error decoding protobuf.");
@ -915,16 +940,15 @@ static int lupb_decode(lua_State *L) {
*/
static int lupb_encode(lua_State *L) {
const upb_msg *msg = lupb_msg_check(L, 1);
const upb_msglayout *layout;
upb_arena *arena = lupb_arena_pushnew(L);
const upb_msgdef *m = lupb_msg_getmsgdef(L, 1);
const upb_msglayout *layout = upb_msgdef_layout(m);
int options = lupb_getoptions(L, 2);
upb_arena *arena;
size_t size;
char *result;
lua_getiuservalue(L, 1, LUPB_MSGDEF_INDEX);
layout = upb_msgdef_layout(lupb_msgdef_check(L, -1));
lua_pop(L, 1);
result = upb_encode(msg, (const void*)layout, arena, &size);
arena = lupb_arena_pushnew(L);
result = upb_encode_ex(msg, (const void*)layout, options, arena, &size);
if (!result) {
lua_pushstring(L, "Error encoding protobuf.");
@ -936,11 +960,101 @@ static int lupb_encode(lua_State *L) {
return 1;
}
/**
* lupb_jsondecode()
*
* Handles:
* text_string = upb.json_decode(MessageClass, json_str, {upb.JSONDEC_IGNOREUNKNOWN})
*/
static int lupb_jsondecode(lua_State *L) {
size_t len;
const upb_msgdef *m = lupb_msgdef_check(L, 1);
const char *json = lua_tolstring(L, 2, &len);
int options = lupb_getoptions(L, 3);
upb_msg *msg;
upb_arena *arena;
upb_status status;
msg = lupb_msg_pushnew(L, 1);
arena = lupb_arenaget(L, -1);
upb_status_clear(&status);
upb_json_decode(json, len, msg, m, NULL, options, arena, &status);
lupb_checkstatus(L, &status);
return 1;
}
/**
* lupb_jsonencode()
*
* Handles:
* text_string = upb.json_encode(msg, {upb.JSONENC_EMITDEFAULTS})
*/
static int lupb_jsonencode(lua_State *L) {
upb_msg *msg = lupb_msg_check(L, 1);
const upb_msgdef *m = lupb_msg_getmsgdef(L, 1);
int options = lupb_getoptions(L, 2);
char buf[1024];
size_t size;
upb_status status;
upb_status_clear(&status);
size = upb_json_encode(msg, m, NULL, options, buf, sizeof(buf), &status);
lupb_checkstatus(L, &status);
if (size < sizeof(buf)) {
lua_pushlstring(L, buf, size);
} else {
char *ptr = malloc(size + 1);
upb_json_encode(msg, m, NULL, options, ptr, size + 1, &status);
lupb_checkstatus(L, &status);
lua_pushlstring(L, ptr, size);
free(ptr);
}
return 1;
}
/**
* lupb_textencode()
*
* Handles:
* text_string = upb.text_encode(msg, {upb.TXTENC_SINGLELINE})
*/
static int lupb_textencode(lua_State *L) {
upb_msg *msg = lupb_msg_check(L, 1);
const upb_msgdef *m = lupb_msg_getmsgdef(L, 1);
int options = lupb_getoptions(L, 2);
char buf[1024];
size_t size;
size = upb_text_encode(msg, m, NULL, options, buf, sizeof(buf));
if (size < sizeof(buf)) {
lua_pushlstring(L, buf, size);
} else {
char *ptr = malloc(size + 1);
upb_text_encode(msg, m, NULL, options, ptr, size + 1);
lua_pushlstring(L, ptr, size);
free(ptr);
}
return 1;
}
static void lupb_setfieldi(lua_State *L, const char *field, int i) {
lua_pushinteger(L, i);
lua_setfield(L, -2, field);
}
static const struct luaL_Reg lupb_msg_toplevel_m[] = {
{"Array", lupb_array_new},
{"Map", lupb_map_new},
{"decode", lupb_decode},
{"encode", lupb_encode},
{"json_decode", lupb_jsondecode},
{"json_encode", lupb_jsonencode},
{"text_encode", lupb_textencode},
{NULL, NULL}
};
@ -952,5 +1066,17 @@ void lupb_msg_registertypes(lua_State *L) {
lupb_register_type(L, LUPB_MAP, NULL, lupb_map_mm);
lupb_register_type(L, LUPB_MSG, NULL, lupb_msg_mm);
lupb_setfieldi(L, "TXTENC_SINGLELINE", UPB_TXTENC_SINGLELINE);
lupb_setfieldi(L, "TXTENC_SKIPUNKNOWN", UPB_TXTENC_SKIPUNKNOWN);
lupb_setfieldi(L, "TXTENC_NOSORT", UPB_TXTENC_NOSORT);
lupb_setfieldi(L, "ENCODE_DETERMINISTIC", UPB_ENCODE_DETERMINISTIC);
lupb_setfieldi(L, "ENCODE_SKIPUNKNOWN", UPB_ENCODE_SKIPUNKNOWN);
lupb_setfieldi(L, "JSONENC_EMITDEFAULTS", UPB_JSONENC_EMITDEFAULTS);
lupb_setfieldi(L, "JSONENC_PROTONAMES", UPB_JSONENC_PROTONAMES);
lupb_setfieldi(L, "JSONDEC_IGNOREUNKNOWN", UPB_JSONDEC_IGNOREUNKNOWN);
lupb_cacheinit(L);
}

@ -84,6 +84,24 @@ int lua_getiuservalue(lua_State *L, int index, int n) {
}
#endif
/* We use this function as the __index metamethod when a type has both methods
* and an __index metamethod. */
int lupb_indexmm(lua_State *L) {
/* Look up in __index table (which is a closure param). */
lua_pushvalue(L, 2);
lua_rawget(L, lua_upvalueindex(1));
if (!lua_isnil(L, -1)) {
return 1;
}
/* Not found, chain to user __index metamethod. */
lua_pushvalue(L, lua_upvalueindex(2));
lua_pushvalue(L, 1);
lua_pushvalue(L, 2);
lua_call(L, 2, 1);
return 1;
}
void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m,
const luaL_Reg *mm) {
luaL_newmetatable(L, name);
@ -93,14 +111,17 @@ void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m,
}
if (m) {
/* Methods go in the mt's __index method. This implies that you can'
* implement __index and also have methods. */
lua_getfield(L, -1, "__index");
lupb_assert(L, lua_isnil(L, -1));
lua_pop(L, 1);
lua_createtable(L, 0, 0);
lua_createtable(L, 0, 0); /* __index table */
lupb_setfuncs(L, m);
/* Methods go in the mt's __index slot. If the user also specified an
* __index metamethod, use our custom lupb_indexmm() that can check both. */
lua_getfield(L, -2, "__index");
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
} else {
lua_pushcclosure(L, &lupb_indexmm, 2);
}
lua_setfield(L, -2, "__index");
}

@ -75,7 +75,7 @@ void lupb_def_registertypes(lua_State *L);
/** From msg.c. ***************************************************************/
int lupb_msg_pushnew(lua_State *L);
int lupb_msgdef_call(lua_State *L);
upb_arena *lupb_arena_pushnew(lua_State *L);
void lupb_msg_registertypes(lua_State *L);

@ -19,7 +19,7 @@ class LuaGenerator : public protoc::CodeGenerator {
};
static std::string StripExtension(absl::string_view fname) {
size_t lastdot = fname.find_last_of(".");
size_t lastdot = fname.find_last_of('.');
if (lastdot == std::string::npos) {
return std::string(fname);
}

@ -150,11 +150,23 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg,
UPB_NORETURN static void decode_err(upb_decstate *d) { UPB_LONGJMP(d->err, 1); }
// We don't want to mark this NORETURN, see comment in .h.
// Unfortunately this code to suppress the warning doesn't appear to be working.
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-warning-option"
#pragma clang diagnostic ignored "-Wsuggest-attribute"
#endif
const char *fastdecode_err(upb_decstate *d) {
longjmp(d->err, 1);
return NULL;
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
const uint8_t upb_utf8_offsets[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@ -219,13 +231,20 @@ static const char *decode_varint64(upb_decstate *d, const char *ptr,
}
UPB_FORCEINLINE
static const char *decode_varint32(upb_decstate *d, const char *ptr,
static const char *decode_tag(upb_decstate *d, const char *ptr,
uint32_t *val) {
uint64_t u64;
ptr = decode_varint64(d, ptr, &u64);
if (u64 > UINT32_MAX) decode_err(d);
*val = (uint32_t)u64;
return ptr;
uint64_t byte = (uint8_t)*ptr;
if (UPB_LIKELY((byte & 0x80) == 0)) {
*val = byte;
return ptr + 1;
} else {
const char *start = ptr;
decode_vret res = decode_longvarint64(ptr, byte);
ptr = res.ptr;
*val = res.val;
if (!ptr || *val > UINT32_MAX || ptr - start > 5) decode_err(d);
return ptr;
}
}
static void decode_munge(int type, wireval *val) {
@ -545,7 +564,7 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg,
int op;
UPB_ASSERT(ptr < d->limit_ptr);
ptr = decode_varint32(d, ptr, &tag);
ptr = decode_tag(d, ptr, &tag);
field_number = tag >> 3;
wire_type = tag & 7;
@ -573,13 +592,15 @@ static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg,
break;
case UPB_WIRE_TYPE_DELIMITED: {
int ndx = field->descriptortype;
uint64_t size;
if (_upb_isrepeated(field)) ndx += 18;
ptr = decode_varint32(d, ptr, &val.size);
if (val.size >= INT32_MAX ||
ptr - d->end + (int32_t)val.size > d->limit) {
ptr = decode_varint64(d, ptr, &size);
if (size >= INT32_MAX ||
ptr - d->end + (int32_t)size > d->limit) {
decode_err(d); /* Length overflow. */
}
op = delim_ops[ndx];
val.size = size;
break;
}
case UPB_WIRE_TYPE_START_GROUP:
@ -643,6 +664,14 @@ const char *fastdecode_generic(struct upb_decstate *d, const char *ptr,
return decode_msg(d, ptr, msg, decode_totablep(table));
}
static bool decode_top(struct upb_decstate *d, const char *buf, void *msg,
const upb_msglayout *l) {
if (!decode_tryfastdispatch(d, &buf, msg, l)) {
decode_msg(d, buf, msg, l);
}
return d->end_group == DECODE_NOGROUP;
}
bool _upb_decode(const char *buf, size_t size, void *msg,
const upb_msglayout *l, upb_arena *arena, int options) {
bool ok;
@ -670,19 +699,18 @@ bool _upb_decode(const char *buf, size_t size, void *msg,
state.end_group = DECODE_NOGROUP;
state.arena.head = arena->head;
state.arena.last_size = arena->last_size;
state.arena.cleanups = arena->cleanups;
state.arena.parent = arena;
if (UPB_UNLIKELY(UPB_SETJMP(state.err))) {
ok = false;
} else {
if (!decode_tryfastdispatch(&state, &buf, msg, l)) {
decode_msg(&state, buf, msg, l);
}
ok = state.end_group == DECODE_NOGROUP;
ok = decode_top(&state, buf, msg, l);
}
arena->head.ptr = state.arena.head.ptr;
arena->head.end = state.arena.head.end;
arena->cleanups = state.arena.cleanups;
return ok;
}

@ -15,6 +15,8 @@ extern "C" {
#endif
enum {
/* If set, strings will alias the input buffer instead of copying into the
* arena. */
UPB_DECODE_ALIAS = 1,
};

@ -14,7 +14,7 @@
/* Must be last. */
#include "upb/port_def.inc"
#define DECODE_NOGROUP -1
#define DECODE_NOGROUP (uint32_t)-1
typedef struct upb_decstate {
const char *end; /* Can read up to 16 bytes slop beyond this. */

@ -8,6 +8,9 @@
#include <string.h>
#include "google/protobuf/descriptor.upb.h"
#include "upb/reflection.h"
/* Must be last. */
#include "upb/port_def.inc"
typedef struct {
@ -37,7 +40,6 @@ struct upb_fielddef {
uint32_t number_;
uint16_t index_;
uint16_t layout_index;
uint32_t selector_base; /* Used to index into a upb::Handlers table. */
bool is_extension_;
bool lazy_;
bool packed_;
@ -50,8 +52,6 @@ struct upb_msgdef {
const upb_msglayout *layout;
const upb_filedef *file;
const char *full_name;
uint32_t selector_count;
uint32_t submsg_field_count;
/* Tables for looking up fields by number and name. */
upb_inttable itof;
@ -93,17 +93,18 @@ struct upb_filedef {
const char *package;
const char *phpprefix;
const char *phpnamespace;
upb_syntax_t syntax;
const upb_filedef **deps;
const upb_msgdef *msgs;
const upb_enumdef *enums;
const upb_fielddef *exts;
const upb_symtab *symtab;
int dep_count;
int msg_count;
int enum_count;
int ext_count;
upb_syntax_t syntax;
};
struct upb_symtab {
@ -180,30 +181,6 @@ int cmp_fields(const void *p1, const void *p2) {
return field_rank(f1) - field_rank(f2);
}
/* A few implementation details of handlers. We put these here to avoid
* a def -> handlers dependency. */
#define UPB_STATIC_SELECTOR_COUNT 3 /* Warning: also in upb/handlers.h. */
static uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) {
return upb_fielddef_isseq(f) ? 2 : 0;
}
static uint32_t upb_handlers_selectorcount(const upb_fielddef *f) {
uint32_t ret = 1;
if (upb_fielddef_isseq(f)) ret += 2; /* STARTSEQ/ENDSEQ */
if (upb_fielddef_isstring(f)) ret += 2; /* [STRING]/STARTSTR/ENDSTR */
if (upb_fielddef_issubmsg(f)) {
/* ENDSUBMSG (STARTSUBMSG is at table beginning) */
ret += 0;
if (upb_fielddef_lazy(f)) {
/* STARTSTR/ENDSTR/STRING (for lazy) */
ret += 3;
}
}
return ret;
}
static void upb_status_setoom(upb_status *status) {
upb_status_seterrmsg(status, "out of memory");
}
@ -295,8 +272,7 @@ bool upb_enumdef_ntoi(const upb_enumdef *def, const char *name,
const char *upb_enumdef_iton(const upb_enumdef *def, int32_t num) {
upb_value v;
return upb_inttable_lookup32(&def->iton, num, &v) ?
upb_value_getcstr(v) : NULL;
return upb_inttable_lookup(&def->iton, num, &v) ? upb_value_getcstr(v) : NULL;
}
const char *upb_enum_iter_name(upb_enum_iter *iter) {
@ -385,10 +361,6 @@ const char *upb_fielddef_jsonname(const upb_fielddef *f) {
return f->json_name;
}
uint32_t upb_fielddef_selectorbase(const upb_fielddef *f) {
return f->selector_base;
}
const upb_filedef *upb_fielddef_file(const upb_fielddef *f) {
return f->file;
}
@ -406,6 +378,23 @@ const upb_oneofdef *upb_fielddef_realcontainingoneof(const upb_fielddef *f) {
return f->oneof;
}
upb_msgval upb_fielddef_default(const upb_fielddef *f) {
UPB_ASSERT(!upb_fielddef_issubmsg(f));
upb_msgval ret;
if (upb_fielddef_isstring(f)) {
str_t *str = f->defaultval.str;
if (str) {
ret.str_val.data = str->str;
ret.str_val.size = str->len;
} else {
ret.str_val.size = 0;
}
} else {
memcpy(&ret, &f->defaultval, 8);
}
return ret;
}
static void chkdefaulttype(const upb_fielddef *f, int ctype) {
UPB_UNUSED(f);
UPB_UNUSED(ctype);
@ -534,18 +523,10 @@ upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m) {
return m->file->syntax;
}
size_t upb_msgdef_selectorcount(const upb_msgdef *m) {
return m->selector_count;
}
uint32_t upb_msgdef_submsgfieldcount(const upb_msgdef *m) {
return m->submsg_field_count;
}
const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) {
upb_value val;
return upb_inttable_lookup32(&m->itof, i, &val) ?
upb_value_getconstptr(val) : NULL;
return upb_inttable_lookup(&m->itof, i, &val) ? upb_value_getconstptr(val)
: NULL;
}
const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name,
@ -753,8 +734,8 @@ const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o,
const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num) {
upb_value val;
return upb_inttable_lookup32(&o->itof, num, &val) ?
upb_value_getptr(val) : NULL;
return upb_inttable_lookup(&o->itof, num, &val) ? upb_value_getptr(val)
: NULL;
}
void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o) {
@ -823,6 +804,10 @@ const upb_enumdef *upb_filedef_enum(const upb_filedef *f, int i) {
return i < 0 || i >= f->enum_count ? NULL : &f->enums[i];
}
const upb_symtab *upb_filedef_symtab(const upb_filedef *f) {
return f->symtab;
}
void upb_symtab_free(upb_symtab *s) {
upb_arena_free(s->arena);
upb_gfree(s);
@ -840,8 +825,8 @@ upb_symtab *upb_symtab_new(void) {
s->bytes_loaded = 0;
alloc = upb_arena_alloc(s->arena);
if (!upb_strtable_init2(&s->syms, UPB_CTYPE_CONSTPTR, 32, alloc) ||
!upb_strtable_init2(&s->files, UPB_CTYPE_CONSTPTR, 4, alloc)) {
if (!upb_strtable_init(&s->syms, 32, s->arena) ||
!upb_strtable_init(&s->files, 4, s->arena)) {
upb_arena_free(s->arena);
upb_gfree(s);
s = NULL;
@ -897,14 +882,13 @@ int upb_symtab_filecount(const upb_symtab *s) {
typedef struct {
upb_symtab *symtab;
upb_filedef *file; /* File we are building. */
upb_arena *file_arena; /* Allocate defs here. */
upb_alloc *alloc; /* Alloc of file_arena, for tables. */
upb_arena *arena; /* Allocate defs here. */
const upb_msglayout **layouts; /* NULL if we should build layouts. */
upb_status *status; /* Record errors here. */
jmp_buf err; /* longjmp() on error. */
} symtab_addctx;
UPB_NORETURN UPB_NOINLINE
UPB_NORETURN UPB_NOINLINE UPB_PRINTF(2, 3)
static void symtab_errf(symtab_addctx *ctx, const char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
@ -920,7 +904,7 @@ static void symtab_oomerr(symtab_addctx *ctx) {
}
void *symtab_alloc(symtab_addctx *ctx, size_t bytes) {
void *ret = upb_arena_malloc(ctx->file_arena, bytes);
void *ret = upb_arena_malloc(ctx->arena, bytes);
if (!ret) symtab_oomerr(ctx);
return ret;
}
@ -1027,13 +1011,21 @@ static void make_layout(symtab_addctx *ctx, const upb_msgdef *m) {
upb_msg_field_iter it;
upb_msg_oneof_iter oit;
size_t hasbit;
size_t submsg_count = m->submsg_field_count;
size_t field_count = upb_msgdef_numfields(m);
size_t submsg_count = 0;
const upb_msglayout **submsgs;
upb_msglayout_field *fields;
memset(l, 0, sizeof(*l) + sizeof(_upb_fasttable_entry));
fields = symtab_alloc(ctx, upb_msgdef_numfields(m) * sizeof(*fields));
/* Count sub-messages. */
for (size_t i = 0; i < field_count; i++) {
if (upb_fielddef_issubmsg(&m->fields[i])) {
submsg_count++;
}
}
fields = symtab_alloc(ctx, field_count * sizeof(*fields));
submsgs = symtab_alloc(ctx, submsg_count * sizeof(*submsgs));
l->field_count = upb_msgdef_numfields(m);
@ -1184,51 +1176,8 @@ static void make_layout(symtab_addctx *ctx, const upb_msgdef *m) {
assign_layout_indices(m, fields);
}
static void assign_msg_indices(symtab_addctx *ctx, upb_msgdef *m) {
/* Sort fields. upb internally relies on UPB_TYPE_MESSAGE fields having the
* lowest indexes, but we do not publicly guarantee this. */
upb_msg_field_iter j;
int i;
uint32_t selector;
int n = upb_msgdef_numfields(m);
upb_fielddef **fields;
if (n == 0) {
m->selector_count = UPB_STATIC_SELECTOR_COUNT;
m->submsg_field_count = 0;
return;
}
fields = upb_gmalloc(n * sizeof(*fields));
m->submsg_field_count = 0;
for(i = 0, upb_msg_field_begin(&j, m);
!upb_msg_field_done(&j);
upb_msg_field_next(&j), i++) {
upb_fielddef *f = upb_msg_iter_field(&j);
UPB_ASSERT(f->msgdef == m);
if (upb_fielddef_issubmsg(f)) {
m->submsg_field_count++;
}
fields[i] = f;
}
qsort(fields, n, sizeof(*fields), cmp_fields);
selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count;
for (i = 0; i < n; i++) {
upb_fielddef *f = fields[i];
f->index_ = i;
f->selector_base = selector + upb_handlers_selectorbaseoffset(f);
selector += upb_handlers_selectorcount(f);
}
m->selector_count = selector;
upb_gfree(fields);
}
static char *strviewdup(symtab_addctx *ctx, upb_strview view) {
return upb_strdup2(view.data, view.size, ctx->alloc);
return upb_strdup2(view.data, view.size, ctx->arena);
}
static bool streql2(const char *a, size_t n, const char *b) {
@ -1339,9 +1288,9 @@ static void symtab_add(symtab_addctx *ctx, const char *name, upb_value v) {
if (upb_strtable_lookup(&ctx->symtab->syms, name, NULL)) {
symtab_errf(ctx, "duplicate symbol '%s'", name);
}
upb_alloc *alloc = upb_arena_alloc(ctx->symtab->arena);
size_t len = strlen(name);
CHK_OOM(upb_strtable_insert3(&ctx->symtab->syms, name, len, v, alloc));
CHK_OOM(upb_strtable_insert(&ctx->symtab->syms, name, len, v,
ctx->symtab->arena));
}
/* Given a symbol and the base symbol inside which it is defined, find the
@ -1374,7 +1323,8 @@ static const void *symtab_resolve(symtab_addctx *ctx, const upb_fielddef *f,
}
notfound:
symtab_errf(ctx, "couldn't resolve name '%s'", sym.data);
symtab_errf(ctx, "couldn't resolve name '" UPB_STRVIEW_FORMAT "'",
UPB_STRVIEW_ARGS(sym));
}
static void create_oneofdef(
@ -1392,10 +1342,10 @@ static void create_oneofdef(
v = pack_def(o, UPB_DEFTYPE_ONEOF);
symtab_add(ctx, o->full_name, v);
CHK_OOM(upb_strtable_insert3(&m->ntof, name.data, name.size, v, ctx->alloc));
CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, v, ctx->arena));
CHK_OOM(upb_inttable_init2(&o->itof, UPB_CTYPE_CONSTPTR, ctx->alloc));
CHK_OOM(upb_strtable_init2(&o->ntof, UPB_CTYPE_CONSTPTR, 4, ctx->alloc));
CHK_OOM(upb_inttable_init(&o->itof, ctx->arena));
CHK_OOM(upb_strtable_init(&o->ntof, 4, ctx->arena));
}
static str_t *newstr(symtab_addctx *ctx, const char *data, size_t len) {
@ -1518,7 +1468,7 @@ static void parse_default(symtab_addctx *ctx, const char *str, size_t len,
return;
invalid:
symtab_errf(ctx, "Invalid default '%.*s' for field %f", (int)len, str,
symtab_errf(ctx, "Invalid default '%.*s' for field %s", (int)len, str,
upb_fielddef_fullname(f));
}
@ -1552,7 +1502,6 @@ static void set_default_default(symtab_addctx *ctx, upb_fielddef *f) {
static void create_fielddef(
symtab_addctx *ctx, const char *prefix, upb_msgdef *m,
const google_protobuf_FieldDescriptorProto *field_proto) {
upb_alloc *alloc = ctx->alloc;
upb_fielddef *f;
const google_protobuf_FieldOptions *options;
upb_strview name;
@ -1588,7 +1537,8 @@ static void create_fielddef(
upb_value v, field_v, json_v;
size_t json_size;
f = (upb_fielddef*)&m->fields[m->field_count++];
f = (upb_fielddef*)&m->fields[m->field_count];
f->index_ = m->field_count++;
f->msgdef = m;
f->is_extension_ = false;
@ -1609,12 +1559,12 @@ static void create_fielddef(
v = upb_value_constptr(f);
json_size = strlen(json_name);
CHK_OOM(
upb_strtable_insert3(&m->ntof, name.data, name.size, field_v, alloc));
CHK_OOM(upb_inttable_insert2(&m->itof, field_number, v, alloc));
CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, field_v,
ctx->arena));
CHK_OOM(upb_inttable_insert(&m->itof, field_number, v, ctx->arena));
if (strcmp(shortname, json_name) != 0) {
upb_strtable_insert3(&m->ntof, json_name, json_size, json_v, alloc);
upb_strtable_insert(&m->ntof, json_name, json_size, json_v, ctx->arena);
}
if (ctx->layouts) {
@ -1677,15 +1627,16 @@ static void create_fielddef(
symtab_errf(ctx, "oneof_index out of range (%s)", f->full_name);
}
oneof = (upb_oneofdef*)&m->oneofs[oneof_index];
oneof = (upb_oneofdef *)&m->oneofs[oneof_index];
f->oneof = oneof;
oneof->field_count++;
if (f->proto3_optional_) {
oneof->synthetic = true;
}
CHK_OOM(upb_inttable_insert2(&oneof->itof, f->number_, v, alloc));
CHK_OOM(upb_strtable_insert3(&oneof->ntof, name.data, name.size, v, alloc));
CHK_OOM(upb_inttable_insert(&oneof->itof, f->number_, v, ctx->arena));
CHK_OOM(
upb_strtable_insert(&oneof->ntof, name.data, name.size, v, ctx->arena));
} else {
f->oneof = NULL;
if (f->proto3_optional_) {
@ -1728,8 +1679,8 @@ static void create_enumdef(
symtab_add(ctx, e->full_name, pack_def(e, UPB_DEFTYPE_ENUM));
values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n);
CHK_OOM(upb_strtable_init2(&e->ntoi, UPB_CTYPE_INT32, n, ctx->alloc));
CHK_OOM(upb_inttable_init2(&e->iton, UPB_CTYPE_CSTR, ctx->alloc));
CHK_OOM(upb_strtable_init(&e->ntoi, n, ctx->arena));
CHK_OOM(upb_inttable_init(&e->iton, ctx->arena));
e->file = ctx->file;
e->defaultval = 0;
@ -1756,16 +1707,15 @@ static void create_enumdef(
}
CHK_OOM(name2)
CHK_OOM(
upb_strtable_insert3(&e->ntoi, name2, strlen(name2), v, ctx->alloc));
CHK_OOM(upb_strtable_insert(&e->ntoi, name2, strlen(name2), v, ctx->arena));
if (!upb_inttable_lookup(&e->iton, num, NULL)) {
upb_value v = upb_value_cstr(name2);
CHK_OOM(upb_inttable_insert2(&e->iton, num, v, ctx->alloc));
CHK_OOM(upb_inttable_insert(&e->iton, num, v, ctx->arena));
}
}
upb_inttable_compact2(&e->iton, ctx->alloc);
upb_inttable_compact(&e->iton, ctx->arena);
}
static void create_msgdef(symtab_addctx *ctx, const char *prefix,
@ -1789,9 +1739,8 @@ static void create_msgdef(symtab_addctx *ctx, const char *prefix,
oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof);
fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field);
CHK_OOM(upb_inttable_init2(&m->itof, UPB_CTYPE_CONSTPTR, ctx->alloc));
CHK_OOM(upb_strtable_init2(&m->ntof, UPB_CTYPE_CONSTPTR, n_oneof + n_field,
ctx->alloc));
CHK_OOM(upb_inttable_init(&m->itof, ctx->arena));
CHK_OOM(upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena));
m->file = ctx->file;
m->map_entry = false;
@ -1823,10 +1772,9 @@ static void create_msgdef(symtab_addctx *ctx, const char *prefix,
create_fielddef(ctx, m->full_name, m, fields[i]);
}
assign_msg_indices(ctx, m);
finalize_oneofs(ctx, m);
assign_msg_wellknowntype(m);
upb_inttable_compact2(&m->itof, ctx->alloc);
upb_inttable_compact(&m->itof, ctx->arena);
/* This message is built. Now build nested messages and enums. */
@ -2055,19 +2003,18 @@ static void build_filedef(
}
static void remove_filedef(upb_symtab *s, upb_filedef *file) {
upb_alloc *alloc = upb_arena_alloc(s->arena);
int i;
for (i = 0; i < file->msg_count; i++) {
const char *name = file->msgs[i].full_name;
upb_strtable_remove3(&s->syms, name, strlen(name), NULL, alloc);
upb_strtable_remove(&s->syms, name, strlen(name), NULL);
}
for (i = 0; i < file->enum_count; i++) {
const char *name = file->enums[i].full_name;
upb_strtable_remove3(&s->syms, name, strlen(name), NULL, alloc);
upb_strtable_remove(&s->syms, name, strlen(name), NULL);
}
for (i = 0; i < file->ext_count; i++) {
const char *name = file->exts[i].full_name;
upb_strtable_remove3(&s->syms, name, strlen(name), NULL, alloc);
upb_strtable_remove(&s->syms, name, strlen(name), NULL);
}
}
@ -2085,14 +2032,14 @@ static const upb_filedef *_upb_symtab_addfile(
ctx.file = file;
ctx.symtab = s;
ctx.file_arena = file_arena;
ctx.alloc = upb_arena_alloc(file_arena);
ctx.arena = file_arena;
ctx.layouts = layouts;
ctx.status = status;
file->msg_count = 0;
file->enum_count = 0;
file->ext_count = 0;
file->symtab = s;
if (UPB_UNLIKELY(UPB_SETJMP(ctx.err))) {
UPB_ASSERT(!upb_ok(status));
@ -2100,8 +2047,8 @@ static const upb_filedef *_upb_symtab_addfile(
file = NULL;
} else {
build_filedef(&ctx, file, file_proto);
upb_strtable_insert3(&s->files, file->name, strlen(file->name),
upb_value_constptr(file), ctx.alloc);
upb_strtable_insert(&s->files, file->name, strlen(file->name),
upb_value_constptr(file), ctx.arena);
UPB_ASSERT(upb_ok(status));
upb_arena_fuse(s->arena, file_arena);
}
@ -2169,4 +2116,8 @@ size_t _upb_symtab_bytesloaded(const upb_symtab *s) {
return s->bytes_loaded;
}
upb_arena *_upb_symtab_arena(const upb_symtab *s) {
return s->arena;
}
#undef CHK_OOM

@ -18,6 +18,7 @@
#include "upb/table.int.h"
#include "google/protobuf/descriptor.upb.h"
/* Must be last. */
#include "upb/port_def.inc"
#ifdef __cplusplus
@ -108,9 +109,6 @@ const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f);
const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f);
const upb_msglayout_field *upb_fielddef_layout(const upb_fielddef *f);
/* Internal only. */
uint32_t upb_fielddef_selectorbase(const upb_fielddef *f);
/* upb_oneofdef ***************************************************************/
typedef upb_inttable_iter upb_oneof_iter;
@ -195,10 +193,6 @@ UPB_INLINE const upb_fielddef *upb_msgdef_ntofz(const upb_msgdef *m,
return upb_msgdef_ntof(m, name, strlen(name));
}
/* Internal-only. */
size_t upb_msgdef_selectorcount(const upb_msgdef *m);
uint32_t upb_msgdef_submsgfieldcount(const upb_msgdef *m);
/* Lookup of either field or oneof by name. Returns whether either was found.
* If the return is true, then the found def will be set, and the non-found
* one set to NULL. */
@ -277,6 +271,7 @@ int upb_filedef_enumcount(const upb_filedef *f);
const upb_filedef *upb_filedef_dep(const upb_filedef *f, int i);
const upb_msgdef *upb_filedef_msg(const upb_filedef *f, int i);
const upb_enumdef *upb_filedef_enum(const upb_filedef *f, int i);
const upb_symtab *upb_filedef_symtab(const upb_filedef *f);
/* upb_symtab *****************************************************************/
@ -294,6 +289,7 @@ const upb_filedef *upb_symtab_addfile(
upb_symtab *s, const google_protobuf_FileDescriptorProto *file,
upb_status *status);
size_t _upb_symtab_bytesloaded(const upb_symtab *s);
upb_arena *_upb_symtab_arena(const upb_symtab *s);
/* For generated code only: loads a generated descriptor. */
typedef struct upb_def_init {

@ -8,10 +8,13 @@
#include <vector>
#include "upb/def.h"
#include "upb/reflection.h"
#include "upb/upb.hpp"
namespace upb {
typedef upb_msgval MessageValue;
class EnumDefPtr;
class MessageDefPtr;
class OneofDefPtr;
@ -106,6 +109,8 @@ class FieldDefPtr {
float default_float() const { return upb_fielddef_defaultfloat(ptr_); }
double default_double() const { return upb_fielddef_defaultdouble(ptr_); }
MessageValue default_value() const { return upb_fielddef_default(ptr_); }
// The resulting string is always NULL-terminated. If non-NULL, the length
// will be stored in *len.
const char* default_string(size_t* len) const {

@ -32,6 +32,9 @@ typedef struct {
jmp_buf err;
upb_alloc *alloc;
char *buf, *ptr, *limit;
int options;
int depth;
_upb_mapsorter sorter;
} upb_encstate;
static size_t upb_roundup_pow2(size_t bytes) {
@ -131,7 +134,8 @@ static void encode_float(upb_encstate *e, float d) {
encode_fixed32(e, u32);
}
static void encode_tag(upb_encstate *e, int field_number, int wire_type) {
static void encode_tag(upb_encstate *e, uint32_t field_number,
uint8_t wire_type) {
encode_varint(e, (field_number << 3) | wire_type);
}
@ -215,9 +219,11 @@ static void encode_scalar(upb_encstate *e, const void *_field_mem,
if (submsg == NULL) {
return;
}
if (--e->depth == 0) encode_err(e);
encode_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP);
encode_message(e, submsg, subm, &size);
wire_type = UPB_WIRE_TYPE_START_GROUP;
e->depth++;
break;
}
case UPB_DESCRIPTOR_TYPE_MESSAGE: {
@ -227,9 +233,11 @@ static void encode_scalar(upb_encstate *e, const void *_field_mem,
if (submsg == NULL) {
return;
}
if (--e->depth == 0) encode_err(e);
encode_message(e, submsg, subm, &size);
encode_varint(e, size);
wire_type = UPB_WIRE_TYPE_DELIMITED;
e->depth++;
break;
}
default:
@ -310,6 +318,7 @@ static void encode_array(upb_encstate *e, const char *field_mem,
const void *const*start = _upb_array_constptr(arr);
const void *const*ptr = start + arr->len;
const upb_msglayout *subm = m->submsgs[f->submsg_index];
if (--e->depth == 0) encode_err(e);
do {
size_t size;
ptr--;
@ -317,12 +326,14 @@ static void encode_array(upb_encstate *e, const char *field_mem,
encode_message(e, *ptr, subm, &size);
encode_tag(e, f->number, UPB_WIRE_TYPE_START_GROUP);
} while (ptr != start);
e->depth++;
return;
}
case UPB_DESCRIPTOR_TYPE_MESSAGE: {
const void *const*start = _upb_array_constptr(arr);
const void *const*ptr = start + arr->len;
const upb_msglayout *subm = m->submsgs[f->submsg_index];
if (--e->depth == 0) encode_err(e);
do {
size_t size;
ptr--;
@ -330,6 +341,7 @@ static void encode_array(upb_encstate *e, const char *field_mem,
encode_varint(e, size);
encode_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
} while (ptr != start);
e->depth++;
return;
}
}
@ -341,31 +353,48 @@ static void encode_array(upb_encstate *e, const char *field_mem,
}
}
static void encode_mapentry(upb_encstate *e, uint32_t number,
const upb_msglayout *layout,
const upb_map_entry *ent) {
const upb_msglayout_field *key_field = &layout->fields[0];
const upb_msglayout_field *val_field = &layout->fields[1];
size_t pre_len = e->limit - e->ptr;
size_t size;
encode_scalar(e, &ent->v, layout, val_field, false);
encode_scalar(e, &ent->k, layout, key_field, false);
size = (e->limit - e->ptr) - pre_len;
encode_varint(e, size);
encode_tag(e, number, UPB_WIRE_TYPE_DELIMITED);
}
static void encode_map(upb_encstate *e, const char *field_mem,
const upb_msglayout *m, const upb_msglayout_field *f) {
const upb_map *map = *(const upb_map**)field_mem;
const upb_msglayout *entry = m->submsgs[f->submsg_index];
const upb_msglayout_field *key_field = &entry->fields[0];
const upb_msglayout_field *val_field = &entry->fields[1];
upb_strtable_iter i;
if (map == NULL) {
return;
}
const upb_msglayout *layout = m->submsgs[f->submsg_index];
UPB_ASSERT(layout->field_count == 2);
upb_strtable_begin(&i, &map->table);
for(; !upb_strtable_done(&i); upb_strtable_next(&i)) {
size_t pre_len = e->limit - e->ptr;
size_t size;
upb_strview key = upb_strtable_iter_key(&i);
const upb_value val = upb_strtable_iter_value(&i);
if (map == NULL) return;
if (e->options & UPB_ENCODE_DETERMINISTIC) {
_upb_sortedmap sorted;
_upb_mapsorter_pushmap(&e->sorter, layout->fields[0].descriptortype, map,
&sorted);
upb_map_entry ent;
_upb_map_fromkey(key, &ent.k, map->key_size);
_upb_map_fromvalue(val, &ent.v, map->val_size);
encode_scalar(e, &ent.v, entry, val_field, false);
encode_scalar(e, &ent.k, entry, key_field, false);
size = (e->limit - e->ptr) - pre_len;
encode_varint(e, size);
encode_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) {
encode_mapentry(e, f->number, layout, &ent);
}
_upb_mapsorter_popmap(&e->sorter, &sorted);
} else {
upb_strtable_iter i;
upb_strtable_begin(&i, &map->table);
for(; !upb_strtable_done(&i); upb_strtable_next(&i)) {
upb_strview key = upb_strtable_iter_key(&i);
const upb_value val = upb_strtable_iter_value(&i);
upb_map_entry ent;
_upb_map_fromkey(key, &ent.k, map->key_size);
_upb_map_fromvalue(val, &ent.v, map->val_size);
encode_mapentry(e, f->number, layout, &ent);
}
}
}
@ -389,15 +418,16 @@ static void encode_scalarfield(upb_encstate *e, const char *msg,
static void encode_message(upb_encstate *e, const char *msg,
const upb_msglayout *m, size_t *size) {
size_t pre_len = e->limit - e->ptr;
const char *unknown;
size_t unknown_size;
const upb_msglayout_field *f = &m->fields[m->field_count];
const upb_msglayout_field *first = &m->fields[0];
unknown = upb_msg_getunknown(msg, &unknown_size);
if ((e->options & UPB_ENCODE_SKIPUNKNOWN) == 0) {
size_t unknown_size;
const char *unknown = upb_msg_getunknown(msg, &unknown_size);
if (unknown) {
encode_bytes(e, unknown, unknown_size);
if (unknown) {
encode_bytes(e, unknown, unknown_size);
}
}
while (f != first) {
@ -414,28 +444,35 @@ static void encode_message(upb_encstate *e, const char *msg,
*size = (e->limit - e->ptr) - pre_len;
}
char *upb_encode(const void *msg, const upb_msglayout *m, upb_arena *arena,
size_t *size) {
char *upb_encode_ex(const void *msg, const upb_msglayout *l, int options,
upb_arena *arena, size_t *size) {
upb_encstate e;
unsigned depth = (unsigned)options >> 16;
e.alloc = upb_arena_alloc(arena);
e.buf = NULL;
e.limit = NULL;
e.ptr = NULL;
e.depth = depth ? depth : 64;
e.options = options;
_upb_mapsorter_init(&e.sorter);
char *ret = NULL;
if (UPB_SETJMP(e.err)) {
*size = 0;
return NULL;
}
encode_message(&e, msg, m, size);
*size = e.limit - e.ptr;
if (*size == 0) {
static char ch;
return &ch;
ret = NULL;
} else {
UPB_ASSERT(e.ptr);
return e.ptr;
encode_message(&e, msg, l, size);
*size = e.limit - e.ptr;
if (*size == 0) {
static char ch;
ret = &ch;
} else {
UPB_ASSERT(e.ptr);
ret = e.ptr;
}
}
_upb_mapsorter_destroy(&e.sorter);
return ret;
}

@ -7,12 +7,37 @@
#include "upb/msg.h"
/* Must be last. */
#include "upb/port_def.inc"
#ifdef __cplusplus
extern "C" {
#endif
char *upb_encode(const void *msg, const upb_msglayout *l, upb_arena *arena,
size_t *size);
enum {
/* If set, the results of serializing will be deterministic across all
* instances of this binary. There are no guarantees across different
* binary builds.
*
* If your proto contains maps, the encoder will need to malloc()/free()
* memory during encode. */
UPB_ENCODE_DETERMINISTIC = 1,
/* When set, unknown fields are not printed. */
UPB_ENCODE_SKIPUNKNOWN = 2,
};
#define UPB_ENCODE_MAXDEPTH(depth) ((depth) << 16)
char *upb_encode_ex(const void *msg, const upb_msglayout *l, int options,
upb_arena *arena, size_t *size);
UPB_INLINE char *upb_encode(const void *msg, const upb_msglayout *l,
upb_arena *arena, size_t *size) {
return upb_encode_ex(msg, l, 0, arena, size);
}
#include "upb/port_undef.inc"
#ifdef __cplusplus
} /* extern "C" */

@ -1,923 +0,0 @@
/*
** Inline definitions for handlers.h, which are particularly long and a bit
** tricky.
*/
#ifndef UPB_HANDLERS_INL_H_
#define UPB_HANDLERS_INL_H_
#include <limits.h>
#include <stddef.h>
#include "upb/handlers.h"
#include "upb/port_def.inc"
#ifdef __cplusplus
/* Type detection and typedefs for integer types.
* For platforms where there are multiple 32-bit or 64-bit types, we need to be
* able to enumerate them so we can properly create overloads for all variants.
*
* If any platform existed where there were three integer types with the same
* size, this would have to become more complicated. For example, short, int,
* and long could all be 32-bits. Even more diabolically, short, int, long,
* and long long could all be 64 bits and still be standard-compliant.
* However, few platforms are this strange, and it's unlikely that upb will be
* used on the strangest ones. */
/* Can't count on stdint.h limits like INT32_MAX, because in C++ these are
* only defined when __STDC_LIMIT_MACROS are defined before the *first* include
* of stdint.h. We can't guarantee that someone else didn't include these first
* without defining __STDC_LIMIT_MACROS. */
#define UPB_INT32_MAX 0x7fffffffLL
#define UPB_INT32_MIN (-UPB_INT32_MAX - 1)
#define UPB_INT64_MAX 0x7fffffffffffffffLL
#define UPB_INT64_MIN (-UPB_INT64_MAX - 1)
#if INT_MAX == UPB_INT32_MAX && INT_MIN == UPB_INT32_MIN
#define UPB_INT_IS_32BITS 1
#endif
#if LONG_MAX == UPB_INT32_MAX && LONG_MIN == UPB_INT32_MIN
#define UPB_LONG_IS_32BITS 1
#endif
#if LONG_MAX == UPB_INT64_MAX && LONG_MIN == UPB_INT64_MIN
#define UPB_LONG_IS_64BITS 1
#endif
#if LLONG_MAX == UPB_INT64_MAX && LLONG_MIN == UPB_INT64_MIN
#define UPB_LLONG_IS_64BITS 1
#endif
/* We use macros instead of typedefs so we can undefine them later and avoid
* leaking them outside this header file. */
#if UPB_INT_IS_32BITS
#define UPB_INT32_T int
#define UPB_UINT32_T unsigned int
#if UPB_LONG_IS_32BITS
#define UPB_TWO_32BIT_TYPES 1
#define UPB_INT32ALT_T long
#define UPB_UINT32ALT_T unsigned long
#endif /* UPB_LONG_IS_32BITS */
#elif UPB_LONG_IS_32BITS /* && !UPB_INT_IS_32BITS */
#define UPB_INT32_T long
#define UPB_UINT32_T unsigned long
#endif /* UPB_INT_IS_32BITS */
#if UPB_LONG_IS_64BITS
#define UPB_INT64_T long
#define UPB_UINT64_T unsigned long
#if UPB_LLONG_IS_64BITS
#define UPB_TWO_64BIT_TYPES 1
#define UPB_INT64ALT_T long long
#define UPB_UINT64ALT_T unsigned long long
#endif /* UPB_LLONG_IS_64BITS */
#elif UPB_LLONG_IS_64BITS /* && !UPB_LONG_IS_64BITS */
#define UPB_INT64_T long long
#define UPB_UINT64_T unsigned long long
#endif /* UPB_LONG_IS_64BITS */
#undef UPB_INT32_MAX
#undef UPB_INT32_MIN
#undef UPB_INT64_MAX
#undef UPB_INT64_MIN
#undef UPB_INT_IS_32BITS
#undef UPB_LONG_IS_32BITS
#undef UPB_LONG_IS_64BITS
#undef UPB_LLONG_IS_64BITS
namespace upb {
typedef void CleanupFunc(void *ptr);
/* Template to remove "const" from "const T*" and just return "T*".
*
* We define a nonsense default because otherwise it will fail to instantiate as
* a function parameter type even in cases where we don't expect any caller to
* actually match the overload. */
class CouldntRemoveConst {};
template <class T> struct remove_constptr { typedef CouldntRemoveConst type; };
template <class T> struct remove_constptr<const T *> { typedef T *type; };
/* Template that we use below to remove a template specialization from
* consideration if it matches a specific type. */
template <class T, class U> struct disable_if_same { typedef void Type; };
template <class T> struct disable_if_same<T, T> {};
template <class T> void DeletePointer(void *p) { delete static_cast<T>(p); }
template <class T1, class T2>
struct FirstUnlessVoidOrBool {
typedef T1 value;
};
template <class T2>
struct FirstUnlessVoidOrBool<void, T2> {
typedef T2 value;
};
template <class T2>
struct FirstUnlessVoidOrBool<bool, T2> {
typedef T2 value;
};
template<class T, class U>
struct is_same {
static bool value;
};
template<class T>
struct is_same<T, T> {
static bool value;
};
template<class T, class U>
bool is_same<T, U>::value = false;
template<class T>
bool is_same<T, T>::value = true;
/* FuncInfo *******************************************************************/
/* Info about the user's original, pre-wrapped function. */
template <class C, class R = void>
struct FuncInfo {
/* The type of the closure that the function takes (its first param). */
typedef C Closure;
/* The return type. */
typedef R Return;
};
/* Func ***********************************************************************/
/* Func1, Func2, Func3: Template classes representing a function and its
* signature.
*
* Since the function is a template parameter, calling the function can be
* inlined at compile-time and does not require a function pointer at runtime.
* These functions are not bound to a handler data so have no data or cleanup
* handler. */
struct UnboundFunc {
CleanupFunc *GetCleanup() { return nullptr; }
void *GetData() { return nullptr; }
};
template <class R, class P1, R F(P1), class I>
struct Func1 : public UnboundFunc {
typedef R Return;
typedef I FuncInfo;
static R Call(P1 p1) { return F(p1); }
};
template <class R, class P1, class P2, R F(P1, P2), class I>
struct Func2 : public UnboundFunc {
typedef R Return;
typedef I FuncInfo;
static R Call(P1 p1, P2 p2) { return F(p1, p2); }
};
template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I>
struct Func3 : public UnboundFunc {
typedef R Return;
typedef I FuncInfo;
static R Call(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); }
};
template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4),
class I>
struct Func4 : public UnboundFunc {
typedef R Return;
typedef I FuncInfo;
static R Call(P1 p1, P2 p2, P3 p3, P4 p4) { return F(p1, p2, p3, p4); }
};
template <class R, class P1, class P2, class P3, class P4, class P5,
R F(P1, P2, P3, P4, P5), class I>
struct Func5 : public UnboundFunc {
typedef R Return;
typedef I FuncInfo;
static R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
return F(p1, p2, p3, p4, p5);
}
};
/* BoundFunc ******************************************************************/
/* BoundFunc2, BoundFunc3: Like Func2/Func3 except also contains a value that
* shall be bound to the function's second parameter.
*
* Note that the second parameter is a const pointer, but our stored bound value
* is non-const so we can free it when the handlers are destroyed. */
template <class T>
struct BoundFunc {
typedef typename remove_constptr<T>::type MutableP2;
explicit BoundFunc(MutableP2 data_) : data(data_) {}
CleanupFunc *GetCleanup() { return &DeletePointer<MutableP2>; }
MutableP2 GetData() { return data; }
MutableP2 data;
};
template <class R, class P1, class P2, R F(P1, P2), class I>
struct BoundFunc2 : public BoundFunc<P2> {
typedef BoundFunc<P2> Base;
typedef I FuncInfo;
explicit BoundFunc2(typename Base::MutableP2 arg) : Base(arg) {}
};
template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I>
struct BoundFunc3 : public BoundFunc<P2> {
typedef BoundFunc<P2> Base;
typedef I FuncInfo;
explicit BoundFunc3(typename Base::MutableP2 arg) : Base(arg) {}
};
template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4),
class I>
struct BoundFunc4 : public BoundFunc<P2> {
typedef BoundFunc<P2> Base;
typedef I FuncInfo;
explicit BoundFunc4(typename Base::MutableP2 arg) : Base(arg) {}
};
template <class R, class P1, class P2, class P3, class P4, class P5,
R F(P1, P2, P3, P4, P5), class I>
struct BoundFunc5 : public BoundFunc<P2> {
typedef BoundFunc<P2> Base;
typedef I FuncInfo;
explicit BoundFunc5(typename Base::MutableP2 arg) : Base(arg) {}
};
/* FuncSig ********************************************************************/
/* FuncSig1, FuncSig2, FuncSig3: template classes reflecting a function
* *signature*, but without a specific function attached.
*
* These classes contain member functions that can be invoked with a
* specific function to return a Func/BoundFunc class. */
template <class R, class P1>
struct FuncSig1 {
template <R F(P1)>
Func1<R, P1, F, FuncInfo<P1, R> > GetFunc() {
return Func1<R, P1, F, FuncInfo<P1, R> >();
}
};
template <class R, class P1, class P2>
struct FuncSig2 {
template <R F(P1, P2)>
Func2<R, P1, P2, F, FuncInfo<P1, R> > GetFunc() {
return Func2<R, P1, P2, F, FuncInfo<P1, R> >();
}
template <R F(P1, P2)>
BoundFunc2<R, P1, P2, F, FuncInfo<P1, R> > GetFunc(
typename remove_constptr<P2>::type param2) {
return BoundFunc2<R, P1, P2, F, FuncInfo<P1, R> >(param2);
}
};
template <class R, class P1, class P2, class P3>
struct FuncSig3 {
template <R F(P1, P2, P3)>
Func3<R, P1, P2, P3, F, FuncInfo<P1, R> > GetFunc() {
return Func3<R, P1, P2, P3, F, FuncInfo<P1, R> >();
}
template <R F(P1, P2, P3)>
BoundFunc3<R, P1, P2, P3, F, FuncInfo<P1, R> > GetFunc(
typename remove_constptr<P2>::type param2) {
return BoundFunc3<R, P1, P2, P3, F, FuncInfo<P1, R> >(param2);
}
};
template <class R, class P1, class P2, class P3, class P4>
struct FuncSig4 {
template <R F(P1, P2, P3, P4)>
Func4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> > GetFunc() {
return Func4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> >();
}
template <R F(P1, P2, P3, P4)>
BoundFunc4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> > GetFunc(
typename remove_constptr<P2>::type param2) {
return BoundFunc4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> >(param2);
}
};
template <class R, class P1, class P2, class P3, class P4, class P5>
struct FuncSig5 {
template <R F(P1, P2, P3, P4, P5)>
Func5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> > GetFunc() {
return Func5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> >();
}
template <R F(P1, P2, P3, P4, P5)>
BoundFunc5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> > GetFunc(
typename remove_constptr<P2>::type param2) {
return BoundFunc5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> >(param2);
}
};
/* Overloaded template function that can construct the appropriate FuncSig*
* class given a function pointer by deducing the template parameters. */
template <class R, class P1>
inline FuncSig1<R, P1> MatchFunc(R (*f)(P1)) {
UPB_UNUSED(f); /* Only used for template parameter deduction. */
return FuncSig1<R, P1>();
}
template <class R, class P1, class P2>
inline FuncSig2<R, P1, P2> MatchFunc(R (*f)(P1, P2)) {
UPB_UNUSED(f); /* Only used for template parameter deduction. */
return FuncSig2<R, P1, P2>();
}
template <class R, class P1, class P2, class P3>
inline FuncSig3<R, P1, P2, P3> MatchFunc(R (*f)(P1, P2, P3)) {
UPB_UNUSED(f); /* Only used for template parameter deduction. */
return FuncSig3<R, P1, P2, P3>();
}
template <class R, class P1, class P2, class P3, class P4>
inline FuncSig4<R, P1, P2, P3, P4> MatchFunc(R (*f)(P1, P2, P3, P4)) {
UPB_UNUSED(f); /* Only used for template parameter deduction. */
return FuncSig4<R, P1, P2, P3, P4>();
}
template <class R, class P1, class P2, class P3, class P4, class P5>
inline FuncSig5<R, P1, P2, P3, P4, P5> MatchFunc(R (*f)(P1, P2, P3, P4, P5)) {
UPB_UNUSED(f); /* Only used for template parameter deduction. */
return FuncSig5<R, P1, P2, P3, P4, P5>();
}
/* MethodSig ******************************************************************/
/* CallMethod*: a function template that calls a given method. */
template <class R, class C, R (C::*F)()>
R CallMethod0(C *obj) {
return ((*obj).*F)();
}
template <class R, class C, class P1, R (C::*F)(P1)>
R CallMethod1(C *obj, P1 arg1) {
return ((*obj).*F)(arg1);
}
template <class R, class C, class P1, class P2, R (C::*F)(P1, P2)>
R CallMethod2(C *obj, P1 arg1, P2 arg2) {
return ((*obj).*F)(arg1, arg2);
}
template <class R, class C, class P1, class P2, class P3, R (C::*F)(P1, P2, P3)>
R CallMethod3(C *obj, P1 arg1, P2 arg2, P3 arg3) {
return ((*obj).*F)(arg1, arg2, arg3);
}
template <class R, class C, class P1, class P2, class P3, class P4,
R (C::*F)(P1, P2, P3, P4)>
R CallMethod4(C *obj, P1 arg1, P2 arg2, P3 arg3, P4 arg4) {
return ((*obj).*F)(arg1, arg2, arg3, arg4);
}
/* MethodSig: like FuncSig, but for member functions.
*
* GetFunc() returns a normal FuncN object, so after calling GetFunc() no
* more logic is required to special-case methods. */
template <class R, class C>
struct MethodSig0 {
template <R (C::*F)()>
Func1<R, C *, CallMethod0<R, C, F>, FuncInfo<C *, R> > GetFunc() {
return Func1<R, C *, CallMethod0<R, C, F>, FuncInfo<C *, R> >();
}
};
template <class R, class C, class P1>
struct MethodSig1 {
template <R (C::*F)(P1)>
Func2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> > GetFunc() {
return Func2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> >();
}
template <R (C::*F)(P1)>
BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> > GetFunc(
typename remove_constptr<P1>::type param1) {
return BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> >(
param1);
}
};
template <class R, class C, class P1, class P2>
struct MethodSig2 {
template <R (C::*F)(P1, P2)>
Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, FuncInfo<C *, R> >
GetFunc() {
return Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>,
FuncInfo<C *, R> >();
}
template <R (C::*F)(P1, P2)>
BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, FuncInfo<C *, R> >
GetFunc(typename remove_constptr<P1>::type param1) {
return BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>,
FuncInfo<C *, R> >(param1);
}
};
template <class R, class C, class P1, class P2, class P3>
struct MethodSig3 {
template <R (C::*F)(P1, P2, P3)>
Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>, FuncInfo<C *, R> >
GetFunc() {
return Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>,
FuncInfo<C *, R> >();
}
template <R (C::*F)(P1, P2, P3)>
BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>,
FuncInfo<C *, R> >
GetFunc(typename remove_constptr<P1>::type param1) {
return BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>,
FuncInfo<C *, R> >(param1);
}
};
template <class R, class C, class P1, class P2, class P3, class P4>
struct MethodSig4 {
template <R (C::*F)(P1, P2, P3, P4)>
Func5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>,
FuncInfo<C *, R> >
GetFunc() {
return Func5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>,
FuncInfo<C *, R> >();
}
template <R (C::*F)(P1, P2, P3, P4)>
BoundFunc5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>,
FuncInfo<C *, R> >
GetFunc(typename remove_constptr<P1>::type param1) {
return BoundFunc5<R, C *, P1, P2, P3, P4,
CallMethod4<R, C, P1, P2, P3, P4, F>, FuncInfo<C *, R> >(
param1);
}
};
template <class R, class C>
inline MethodSig0<R, C> MatchFunc(R (C::*f)()) {
UPB_UNUSED(f); /* Only used for template parameter deduction. */
return MethodSig0<R, C>();
}
template <class R, class C, class P1>
inline MethodSig1<R, C, P1> MatchFunc(R (C::*f)(P1)) {
UPB_UNUSED(f); /* Only used for template parameter deduction. */
return MethodSig1<R, C, P1>();
}
template <class R, class C, class P1, class P2>
inline MethodSig2<R, C, P1, P2> MatchFunc(R (C::*f)(P1, P2)) {
UPB_UNUSED(f); /* Only used for template parameter deduction. */
return MethodSig2<R, C, P1, P2>();
}
template <class R, class C, class P1, class P2, class P3>
inline MethodSig3<R, C, P1, P2, P3> MatchFunc(R (C::*f)(P1, P2, P3)) {
UPB_UNUSED(f); /* Only used for template parameter deduction. */
return MethodSig3<R, C, P1, P2, P3>();
}
template <class R, class C, class P1, class P2, class P3, class P4>
inline MethodSig4<R, C, P1, P2, P3, P4> MatchFunc(R (C::*f)(P1, P2, P3, P4)) {
UPB_UNUSED(f); /* Only used for template parameter deduction. */
return MethodSig4<R, C, P1, P2, P3, P4>();
}
/* MaybeWrapReturn ************************************************************/
/* Template class that attempts to wrap the return value of the function so it
* matches the expected type. There are two main adjustments it may make:
*
* 1. If the function returns void, make it return the expected type and with
* a value that always indicates success.
* 2. If the function returns bool, make it return the expected type with a
* value that indicates success or failure.
*
* The "expected type" for return is:
* 1. void* for start handlers. If the closure parameter has a different type
* we will cast it to void* for the return in the success case.
* 2. size_t for string buffer handlers.
* 3. bool for everything else. */
/* Template parameters are FuncN type and desired return type. */
template <class F, class R, class Enable = void>
struct MaybeWrapReturn;
/* If the return type matches, return the given function unwrapped. */
template <class F>
struct MaybeWrapReturn<F, typename F::Return> {
typedef F Func;
};
/* Function wrapper that munges the return value from void to (bool)true. */
template <class P1, class P2, void F(P1, P2)>
bool ReturnTrue2(P1 p1, P2 p2) {
F(p1, p2);
return true;
}
template <class P1, class P2, class P3, void F(P1, P2, P3)>
bool ReturnTrue3(P1 p1, P2 p2, P3 p3) {
F(p1, p2, p3);
return true;
}
/* Function wrapper that munges the return value from void to (void*)arg1 */
template <class P1, class P2, void F(P1, P2)>
void *ReturnClosure2(P1 p1, P2 p2) {
F(p1, p2);
return p1;
}
template <class P1, class P2, class P3, void F(P1, P2, P3)>
void *ReturnClosure3(P1 p1, P2 p2, P3 p3) {
F(p1, p2, p3);
return p1;
}
/* Function wrapper that munges the return value from R to void*. */
template <class R, class P1, class P2, R F(P1, P2)>
void *CastReturnToVoidPtr2(P1 p1, P2 p2) {
return F(p1, p2);
}
template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
void *CastReturnToVoidPtr3(P1 p1, P2 p2, P3 p3) {
return F(p1, p2, p3);
}
/* Function wrapper that munges the return value from bool to void*. */
template <class P1, class P2, bool F(P1, P2)>
void *ReturnClosureOrBreak2(P1 p1, P2 p2) {
return F(p1, p2) ? p1 : UPB_BREAK;
}
template <class P1, class P2, class P3, bool F(P1, P2, P3)>
void *ReturnClosureOrBreak3(P1 p1, P2 p2, P3 p3) {
return F(p1, p2, p3) ? p1 : UPB_BREAK;
}
/* For the string callback, which takes five params, returns the size param. */
template <class P1, class P2,
void F(P1, P2, const char *, size_t, const upb_bufhandle *)>
size_t ReturnStringLen(P1 p1, P2 p2, const char *p3, size_t p4,
const upb_bufhandle *p5) {
F(p1, p2, p3, p4, p5);
return p4;
}
/* For the string callback, which takes five params, returns the size param or
* zero. */
template <class P1, class P2,
bool F(P1, P2, const char *, size_t, const upb_bufhandle *)>
size_t ReturnNOr0(P1 p1, P2 p2, const char *p3, size_t p4,
const upb_bufhandle *p5) {
return F(p1, p2, p3, p4, p5) ? p4 : 0;
}
/* If we have a function returning void but want a function returning bool, wrap
* it in a function that returns true. */
template <class P1, class P2, void F(P1, P2), class I>
struct MaybeWrapReturn<Func2<void, P1, P2, F, I>, bool> {
typedef Func2<bool, P1, P2, ReturnTrue2<P1, P2, F>, I> Func;
};
template <class P1, class P2, class P3, void F(P1, P2, P3), class I>
struct MaybeWrapReturn<Func3<void, P1, P2, P3, F, I>, bool> {
typedef Func3<bool, P1, P2, P3, ReturnTrue3<P1, P2, P3, F>, I> Func;
};
/* If our function returns void but we want one returning void*, wrap it in a
* function that returns the first argument. */
template <class P1, class P2, void F(P1, P2), class I>
struct MaybeWrapReturn<Func2<void, P1, P2, F, I>, void *> {
typedef Func2<void *, P1, P2, ReturnClosure2<P1, P2, F>, I> Func;
};
template <class P1, class P2, class P3, void F(P1, P2, P3), class I>
struct MaybeWrapReturn<Func3<void, P1, P2, P3, F, I>, void *> {
typedef Func3<void *, P1, P2, P3, ReturnClosure3<P1, P2, P3, F>, I> Func;
};
/* If our function returns R* but we want one returning void*, wrap it in a
* function that casts to void*. */
template <class R, class P1, class P2, R *F(P1, P2), class I>
struct MaybeWrapReturn<Func2<R *, P1, P2, F, I>, void *,
typename disable_if_same<R *, void *>::Type> {
typedef Func2<void *, P1, P2, CastReturnToVoidPtr2<R *, P1, P2, F>, I> Func;
};
template <class R, class P1, class P2, class P3, R *F(P1, P2, P3), class I>
struct MaybeWrapReturn<Func3<R *, P1, P2, P3, F, I>, void *,
typename disable_if_same<R *, void *>::Type> {
typedef Func3<void *, P1, P2, P3, CastReturnToVoidPtr3<R *, P1, P2, P3, F>, I>
Func;
};
/* If our function returns bool but we want one returning void*, wrap it in a
* function that returns either the first param or UPB_BREAK. */
template <class P1, class P2, bool F(P1, P2), class I>
struct MaybeWrapReturn<Func2<bool, P1, P2, F, I>, void *> {
typedef Func2<void *, P1, P2, ReturnClosureOrBreak2<P1, P2, F>, I> Func;
};
template <class P1, class P2, class P3, bool F(P1, P2, P3), class I>
struct MaybeWrapReturn<Func3<bool, P1, P2, P3, F, I>, void *> {
typedef Func3<void *, P1, P2, P3, ReturnClosureOrBreak3<P1, P2, P3, F>, I>
Func;
};
/* If our function returns void but we want one returning size_t, wrap it in a
* function that returns the size argument. */
template <class P1, class P2,
void F(P1, P2, const char *, size_t, const upb_bufhandle *), class I>
struct MaybeWrapReturn<
Func5<void, P1, P2, const char *, size_t, const upb_bufhandle *, F, I>,
size_t> {
typedef Func5<size_t, P1, P2, const char *, size_t, const upb_bufhandle *,
ReturnStringLen<P1, P2, F>, I> Func;
};
/* If our function returns bool but we want one returning size_t, wrap it in a
* function that returns either 0 or the buf size. */
template <class P1, class P2,
bool F(P1, P2, const char *, size_t, const upb_bufhandle *), class I>
struct MaybeWrapReturn<
Func5<bool, P1, P2, const char *, size_t, const upb_bufhandle *, F, I>,
size_t> {
typedef Func5<size_t, P1, P2, const char *, size_t, const upb_bufhandle *,
ReturnNOr0<P1, P2, F>, I> Func;
};
/* ConvertParams **************************************************************/
/* Template class that converts the function parameters if necessary, and
* ignores the HandlerData parameter if appropriate.
*
* Template parameter is the are FuncN function type. */
template <class F, class T>
struct ConvertParams;
/* Function that discards the handler data parameter. */
template <class R, class P1, R F(P1)>
R IgnoreHandlerData2(void *p1, const void *hd) {
UPB_UNUSED(hd);
return F(static_cast<P1>(p1));
}
template <class R, class P1, class P2Wrapper, class P2Wrapped,
R F(P1, P2Wrapped)>
R IgnoreHandlerData3(void *p1, const void *hd, P2Wrapper p2) {
UPB_UNUSED(hd);
return F(static_cast<P1>(p1), p2);
}
template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
R IgnoreHandlerData4(void *p1, const void *hd, P2 p2, P3 p3) {
UPB_UNUSED(hd);
return F(static_cast<P1>(p1), p2, p3);
}
template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)>
R IgnoreHandlerData5(void *p1, const void *hd, P2 p2, P3 p3, P4 p4) {
UPB_UNUSED(hd);
return F(static_cast<P1>(p1), p2, p3, p4);
}
template <class R, class P1, R F(P1, const char*, size_t)>
R IgnoreHandlerDataIgnoreHandle(void *p1, const void *hd, const char *p2,
size_t p3, const upb_bufhandle *handle) {
UPB_UNUSED(hd);
UPB_UNUSED(handle);
return F(static_cast<P1>(p1), p2, p3);
}
/* Function that casts the handler data parameter. */
template <class R, class P1, class P2, R F(P1, P2)>
R CastHandlerData2(void *c, const void *hd) {
return F(static_cast<P1>(c), static_cast<P2>(hd));
}
template <class R, class P1, class P2, class P3Wrapper, class P3Wrapped,
R F(P1, P2, P3Wrapped)>
R CastHandlerData3(void *c, const void *hd, P3Wrapper p3) {
return F(static_cast<P1>(c), static_cast<P2>(hd), p3);
}
template <class R, class P1, class P2, class P3, class P4, class P5,
R F(P1, P2, P3, P4, P5)>
R CastHandlerData5(void *c, const void *hd, P3 p3, P4 p4, P5 p5) {
return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4, p5);
}
template <class R, class P1, class P2, R F(P1, P2, const char *, size_t)>
R CastHandlerDataIgnoreHandle(void *c, const void *hd, const char *p3,
size_t p4, const upb_bufhandle *handle) {
UPB_UNUSED(handle);
return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4);
}
/* For unbound functions, ignore the handler data. */
template <class R, class P1, R F(P1), class I, class T>
struct ConvertParams<Func1<R, P1, F, I>, T> {
typedef Func2<R, void *, const void *, IgnoreHandlerData2<R, P1, F>, I> Func;
};
template <class R, class P1, class P2, R F(P1, P2), class I,
class R2, class P1_2, class P2_2, class P3_2>
struct ConvertParams<Func2<R, P1, P2, F, I>,
R2 (*)(P1_2, P2_2, P3_2)> {
typedef Func3<R, void *, const void *, P3_2,
IgnoreHandlerData3<R, P1, P3_2, P2, F>, I> Func;
};
/* For StringBuffer only; this ignores both the handler data and the
* upb_bufhandle. */
template <class R, class P1, R F(P1, const char *, size_t), class I, class T>
struct ConvertParams<Func3<R, P1, const char *, size_t, F, I>, T> {
typedef Func5<R, void *, const void *, const char *, size_t,
const upb_bufhandle *, IgnoreHandlerDataIgnoreHandle<R, P1, F>,
I> Func;
};
template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4),
class I, class T>
struct ConvertParams<Func4<R, P1, P2, P3, P4, F, I>, T> {
typedef Func5<R, void *, const void *, P2, P3, P4,
IgnoreHandlerData5<R, P1, P2, P3, P4, F>, I> Func;
};
/* For bound functions, cast the handler data. */
template <class R, class P1, class P2, R F(P1, P2), class I, class T>
struct ConvertParams<BoundFunc2<R, P1, P2, F, I>, T> {
typedef Func2<R, void *, const void *, CastHandlerData2<R, P1, P2, F>, I>
Func;
};
template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I,
class R2, class P1_2, class P2_2, class P3_2>
struct ConvertParams<BoundFunc3<R, P1, P2, P3, F, I>,
R2 (*)(P1_2, P2_2, P3_2)> {
typedef Func3<R, void *, const void *, P3_2,
CastHandlerData3<R, P1, P2, P3_2, P3, F>, I> Func;
};
/* For StringBuffer only; this ignores the upb_bufhandle. */
template <class R, class P1, class P2, R F(P1, P2, const char *, size_t),
class I, class T>
struct ConvertParams<BoundFunc4<R, P1, P2, const char *, size_t, F, I>, T> {
typedef Func5<R, void *, const void *, const char *, size_t,
const upb_bufhandle *,
CastHandlerDataIgnoreHandle<R, P1, P2, F>, I>
Func;
};
template <class R, class P1, class P2, class P3, class P4, class P5,
R F(P1, P2, P3, P4, P5), class I, class T>
struct ConvertParams<BoundFunc5<R, P1, P2, P3, P4, P5, F, I>, T> {
typedef Func5<R, void *, const void *, P3, P4, P5,
CastHandlerData5<R, P1, P2, P3, P4, P5, F>, I> Func;
};
/* utype/ltype are upper/lower-case, ctype is canonical C type, vtype is
* variant C type. */
#define TYPE_METHODS(utype, ltype, ctype, vtype) \
template <> \
struct CanonicalType<vtype> { \
typedef ctype Type; \
}; \
template <> \
inline bool HandlersPtr::SetValueHandler<vtype>( \
FieldDefPtr f, const HandlersPtr::utype##Handler &handler) { \
handler.AddCleanup(ptr()); \
return upb_handlers_set##ltype(ptr(), f.ptr(), handler.handler(), \
&handler.attr()); \
}
TYPE_METHODS(Double, double, double, double)
TYPE_METHODS(Float, float, float, float)
TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64_T)
TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32_T)
TYPE_METHODS(Int64, int64, int64_t, UPB_INT64_T)
TYPE_METHODS(Int32, int32, int32_t, UPB_INT32_T)
TYPE_METHODS(Bool, bool, bool, bool)
#ifdef UPB_TWO_32BIT_TYPES
TYPE_METHODS(Int32, int32, int32_t, UPB_INT32ALT_T)
TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32ALT_T)
#endif
#ifdef UPB_TWO_64BIT_TYPES
TYPE_METHODS(Int64, int64, int64_t, UPB_INT64ALT_T)
TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64ALT_T)
#endif
#undef TYPE_METHODS
template <> struct CanonicalType<Status*> {
typedef Status* Type;
};
template <class F> struct ReturnOf;
template <class R, class P1, class P2>
struct ReturnOf<R (*)(P1, P2)> {
typedef R Return;
};
template <class R, class P1, class P2, class P3>
struct ReturnOf<R (*)(P1, P2, P3)> {
typedef R Return;
};
template <class R, class P1, class P2, class P3, class P4>
struct ReturnOf<R (*)(P1, P2, P3, P4)> {
typedef R Return;
};
template <class R, class P1, class P2, class P3, class P4, class P5>
struct ReturnOf<R (*)(P1, P2, P3, P4, P5)> {
typedef R Return;
};
template <class T>
template <class F>
inline Handler<T>::Handler(F func)
: registered_(false),
cleanup_data_(func.GetData()),
cleanup_func_(func.GetCleanup()) {
attr_.handler_data = func.GetData();
typedef typename ReturnOf<T>::Return Return;
typedef typename ConvertParams<F, T>::Func ConvertedParamsFunc;
typedef typename MaybeWrapReturn<ConvertedParamsFunc, Return>::Func
ReturnWrappedFunc;
handler_ = ReturnWrappedFunc().Call;
/* Set attributes based on what templates can statically tell us about the
* user's function. */
/* If the original function returns void, then we know that we wrapped it to
* always return ok. */
bool always_ok = is_same<typename F::FuncInfo::Return, void>::value;
attr_.alwaysok = always_ok;
/* Closure parameter and return type. */
attr_.closure_type = UniquePtrForType<typename F::FuncInfo::Closure>();
/* We use the closure type (from the first parameter) if the return type is
* void or bool, since these are the two cases we wrap to return the closure's
* type anyway.
*
* This is all nonsense for non START* handlers, but it doesn't matter because
* in that case the value will be ignored. */
typedef typename FirstUnlessVoidOrBool<typename F::FuncInfo::Return,
typename F::FuncInfo::Closure>::value
EffectiveReturn;
attr_.return_closure_type = UniquePtrForType<EffectiveReturn>();
}
template <class T>
inline void Handler<T>::AddCleanup(upb_handlers* h) const {
UPB_ASSERT(!registered_);
registered_ = true;
if (cleanup_func_) {
bool ok = upb_handlers_addcleanup(h, cleanup_data_, cleanup_func_);
UPB_ASSERT(ok);
}
}
} /* namespace upb */
#endif /* __cplusplus */
#undef UPB_TWO_32BIT_TYPES
#undef UPB_TWO_64BIT_TYPES
#undef UPB_INT32_T
#undef UPB_UINT32_T
#undef UPB_INT32ALT_T
#undef UPB_UINT32ALT_T
#undef UPB_INT64_T
#undef UPB_UINT64_T
#undef UPB_INT64ALT_T
#undef UPB_UINT64ALT_T
#include "upb/port_undef.inc"
#endif /* UPB_HANDLERS_INL_H_ */

@ -1,545 +0,0 @@
/*
** TODO(haberman): it's unclear whether a lot of the consistency checks should
** UPB_ASSERT() or return false.
*/
#include "upb/handlers.h"
#include <string.h>
#include "upb/sink.h"
#include "upb/port_def.inc"
struct upb_handlers {
upb_handlercache *cache;
const upb_msgdef *msg;
const upb_handlers **sub;
const void *top_closure_type;
upb_handlers_tabent table[1]; /* Dynamically-sized field handler array. */
};
static void *upb_calloc(upb_arena *arena, size_t size) {
void *mem = upb_malloc(upb_arena_alloc(arena), size);
if (mem) {
memset(mem, 0, size);
}
return mem;
}
/* Defined for the sole purpose of having a unique pointer value for
* UPB_NO_CLOSURE. */
char _upb_noclosure;
/* Given a selector for a STARTSUBMSG handler, resolves to a pointer to the
* subhandlers for this submessage field. */
#define SUBH(h, selector) (h->sub[selector])
/* The selector for a submessage field is the field index. */
#define SUBH_F(h, f) SUBH(h, upb_fielddef_index(f))
static int32_t trygetsel(upb_handlers *h, const upb_fielddef *f,
upb_handlertype_t type) {
upb_selector_t sel;
bool ok;
ok = upb_handlers_getselector(f, type, &sel);
UPB_ASSERT(upb_handlers_msgdef(h) == upb_fielddef_containingtype(f));
UPB_ASSERT(ok);
return sel;
}
static upb_selector_t handlers_getsel(upb_handlers *h, const upb_fielddef *f,
upb_handlertype_t type) {
int32_t sel = trygetsel(h, f, type);
UPB_ASSERT(sel >= 0);
return sel;
}
static const void **returntype(upb_handlers *h, const upb_fielddef *f,
upb_handlertype_t type) {
return &h->table[handlers_getsel(h, f, type)].attr.return_closure_type;
}
static bool doset(upb_handlers *h, int32_t sel, const upb_fielddef *f,
upb_handlertype_t type, upb_func *func,
const upb_handlerattr *attr) {
upb_handlerattr set_attr = UPB_HANDLERATTR_INIT;
const void *closure_type;
const void **context_closure_type;
UPB_ASSERT(!h->table[sel].func);
if (attr) {
set_attr = *attr;
}
/* Check that the given closure type matches the closure type that has been
* established for this context (if any). */
closure_type = set_attr.closure_type;
if (type == UPB_HANDLER_STRING) {
context_closure_type = returntype(h, f, UPB_HANDLER_STARTSTR);
} else if (f && upb_fielddef_isseq(f) &&
type != UPB_HANDLER_STARTSEQ &&
type != UPB_HANDLER_ENDSEQ) {
context_closure_type = returntype(h, f, UPB_HANDLER_STARTSEQ);
} else {
context_closure_type = &h->top_closure_type;
}
if (closure_type && *context_closure_type &&
closure_type != *context_closure_type) {
return false;
}
if (closure_type)
*context_closure_type = closure_type;
/* If this is a STARTSEQ or STARTSTR handler, check that the returned pointer
* matches any pre-existing expectations about what type is expected. */
if (type == UPB_HANDLER_STARTSEQ || type == UPB_HANDLER_STARTSTR) {
const void *return_type = set_attr.return_closure_type;
const void *table_return_type = h->table[sel].attr.return_closure_type;
if (return_type && table_return_type && return_type != table_return_type) {
return false;
}
if (table_return_type && !return_type) {
set_attr.return_closure_type = table_return_type;
}
}
h->table[sel].func = (upb_func*)func;
h->table[sel].attr = set_attr;
return true;
}
/* Returns the effective closure type for this handler (which will propagate
* from outer frames if this frame has no START* handler). Not implemented for
* UPB_HANDLER_STRING at the moment since this is not needed. Returns NULL is
* the effective closure type is unspecified (either no handler was registered
* to specify it or the handler that was registered did not specify the closure
* type). */
const void *effective_closure_type(upb_handlers *h, const upb_fielddef *f,
upb_handlertype_t type) {
const void *ret;
upb_selector_t sel;
UPB_ASSERT(type != UPB_HANDLER_STRING);
ret = h->top_closure_type;
if (upb_fielddef_isseq(f) &&
type != UPB_HANDLER_STARTSEQ &&
type != UPB_HANDLER_ENDSEQ &&
h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSEQ)].func) {
ret = h->table[sel].attr.return_closure_type;
}
if (type == UPB_HANDLER_STRING &&
h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSTR)].func) {
ret = h->table[sel].attr.return_closure_type;
}
/* The effective type of the submessage; not used yet.
* if (type == SUBMESSAGE &&
* h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSUBMSG)].func) {
* ret = h->table[sel].attr.return_closure_type;
* } */
return ret;
}
static upb_handlers *upb_handlers_new(const upb_msgdef *md,
upb_handlercache *cache,
upb_arena *arena) {
int extra;
upb_handlers *h;
extra =
(int)(sizeof(upb_handlers_tabent) * (upb_msgdef_selectorcount(md) - 1));
h = upb_calloc(arena, sizeof(*h) + extra);
if (!h) return NULL;
h->cache = cache;
h->msg = md;
if (upb_msgdef_submsgfieldcount(md) > 0) {
size_t bytes = upb_msgdef_submsgfieldcount(md) * sizeof(*h->sub);
h->sub = upb_calloc(arena, bytes);
if (!h->sub) return NULL;
} else {
h->sub = 0;
}
/* calloc() above initialized all handlers to NULL. */
return h;
}
/* Public interface ***********************************************************/
#define SETTER(name, handlerctype, handlertype) \
bool upb_handlers_set##name(upb_handlers *h, const upb_fielddef *f, \
handlerctype func, \
const upb_handlerattr *attr) { \
int32_t sel = trygetsel(h, f, handlertype); \
return doset(h, sel, f, handlertype, (upb_func *)func, attr); \
}
SETTER(int32, upb_int32_handlerfunc*, UPB_HANDLER_INT32)
SETTER(int64, upb_int64_handlerfunc*, UPB_HANDLER_INT64)
SETTER(uint32, upb_uint32_handlerfunc*, UPB_HANDLER_UINT32)
SETTER(uint64, upb_uint64_handlerfunc*, UPB_HANDLER_UINT64)
SETTER(float, upb_float_handlerfunc*, UPB_HANDLER_FLOAT)
SETTER(double, upb_double_handlerfunc*, UPB_HANDLER_DOUBLE)
SETTER(bool, upb_bool_handlerfunc*, UPB_HANDLER_BOOL)
SETTER(startstr, upb_startstr_handlerfunc*, UPB_HANDLER_STARTSTR)
SETTER(string, upb_string_handlerfunc*, UPB_HANDLER_STRING)
SETTER(endstr, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSTR)
SETTER(startseq, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSEQ)
SETTER(startsubmsg, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSUBMSG)
SETTER(endsubmsg, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSUBMSG)
SETTER(endseq, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSEQ)
#undef SETTER
bool upb_handlers_setunknown(upb_handlers *h, upb_unknown_handlerfunc *func,
const upb_handlerattr *attr) {
return doset(h, UPB_UNKNOWN_SELECTOR, NULL, UPB_HANDLER_INT32,
(upb_func *)func, attr);
}
bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func,
const upb_handlerattr *attr) {
return doset(h, UPB_STARTMSG_SELECTOR, NULL, UPB_HANDLER_INT32,
(upb_func *)func, attr);
}
bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func,
const upb_handlerattr *attr) {
return doset(h, UPB_ENDMSG_SELECTOR, NULL, UPB_HANDLER_INT32,
(upb_func *)func, attr);
}
bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
const upb_handlers *sub) {
UPB_ASSERT(sub);
UPB_ASSERT(upb_fielddef_issubmsg(f));
if (SUBH_F(h, f)) return false; /* Can't reset. */
if (upb_handlers_msgdef(sub) != upb_fielddef_msgsubdef(f)) {
return false;
}
SUBH_F(h, f) = sub;
return true;
}
const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
const upb_fielddef *f) {
UPB_ASSERT(upb_fielddef_issubmsg(f));
return SUBH_F(h, f);
}
upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s,
const void **handler_data) {
upb_func *ret = (upb_func *)h->table[s].func;
if (ret && handler_data) {
*handler_data = h->table[s].attr.handler_data;
}
return ret;
}
bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t sel,
upb_handlerattr *attr) {
if (!upb_handlers_gethandler(h, sel, NULL))
return false;
*attr = h->table[sel].attr;
return true;
}
const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
upb_selector_t sel) {
/* STARTSUBMSG selector in sel is the field's selector base. */
return SUBH(h, sel - UPB_STATIC_SELECTOR_COUNT);
}
const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; }
bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *func) {
return upb_handlercache_addcleanup(h->cache, p, func);
}
upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f) {
switch (upb_fielddef_type(f)) {
case UPB_TYPE_INT32:
case UPB_TYPE_ENUM: return UPB_HANDLER_INT32;
case UPB_TYPE_INT64: return UPB_HANDLER_INT64;
case UPB_TYPE_UINT32: return UPB_HANDLER_UINT32;
case UPB_TYPE_UINT64: return UPB_HANDLER_UINT64;
case UPB_TYPE_FLOAT: return UPB_HANDLER_FLOAT;
case UPB_TYPE_DOUBLE: return UPB_HANDLER_DOUBLE;
case UPB_TYPE_BOOL: return UPB_HANDLER_BOOL;
default: UPB_ASSERT(false); return -1; /* Invalid input. */
}
}
bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type,
upb_selector_t *s) {
uint32_t selector_base = upb_fielddef_selectorbase(f);
switch (type) {
case UPB_HANDLER_INT32:
case UPB_HANDLER_INT64:
case UPB_HANDLER_UINT32:
case UPB_HANDLER_UINT64:
case UPB_HANDLER_FLOAT:
case UPB_HANDLER_DOUBLE:
case UPB_HANDLER_BOOL:
if (!upb_fielddef_isprimitive(f) ||
upb_handlers_getprimitivehandlertype(f) != type)
return false;
*s = selector_base;
break;
case UPB_HANDLER_STRING:
if (upb_fielddef_isstring(f)) {
*s = selector_base;
} else if (upb_fielddef_lazy(f)) {
*s = selector_base + 3;
} else {
return false;
}
break;
case UPB_HANDLER_STARTSTR:
if (upb_fielddef_isstring(f) || upb_fielddef_lazy(f)) {
*s = selector_base + 1;
} else {
return false;
}
break;
case UPB_HANDLER_ENDSTR:
if (upb_fielddef_isstring(f) || upb_fielddef_lazy(f)) {
*s = selector_base + 2;
} else {
return false;
}
break;
case UPB_HANDLER_STARTSEQ:
if (!upb_fielddef_isseq(f)) return false;
*s = selector_base - 2;
break;
case UPB_HANDLER_ENDSEQ:
if (!upb_fielddef_isseq(f)) return false;
*s = selector_base - 1;
break;
case UPB_HANDLER_STARTSUBMSG:
if (!upb_fielddef_issubmsg(f)) return false;
/* Selectors for STARTSUBMSG are at the beginning of the table so that the
* selector can also be used as an index into the "sub" array of
* subhandlers. The indexes for the two into these two tables are the
* same, except that in the handler table the static selectors come first. */
*s = upb_fielddef_index(f) + UPB_STATIC_SELECTOR_COUNT;
break;
case UPB_HANDLER_ENDSUBMSG:
if (!upb_fielddef_issubmsg(f)) return false;
*s = selector_base;
break;
}
UPB_ASSERT((size_t)*s < upb_msgdef_selectorcount(upb_fielddef_containingtype(f)));
return true;
}
/* upb_handlercache ***********************************************************/
struct upb_handlercache {
upb_arena *arena;
upb_inttable tab; /* maps upb_msgdef* -> upb_handlers*. */
upb_handlers_callback *callback;
const void *closure;
};
const upb_handlers *upb_handlercache_get(upb_handlercache *c,
const upb_msgdef *md) {
int i, n;
upb_value v;
upb_handlers *h;
if (upb_inttable_lookupptr(&c->tab, md, &v)) {
return upb_value_getptr(v);
}
h = upb_handlers_new(md, c, c->arena);
v = upb_value_ptr(h);
if (!h) return NULL;
if (!upb_inttable_insertptr(&c->tab, md, v)) return NULL;
c->callback(c->closure, h);
/* For each submessage field, get or create a handlers object and set it as
* the subhandlers. */
n = upb_msgdef_fieldcount(md);
for (i = 0; i < n; i++) {
const upb_fielddef *f = upb_msgdef_field(md, i);
if (upb_fielddef_issubmsg(f)) {
const upb_msgdef *subdef = upb_fielddef_msgsubdef(f);
const upb_handlers *sub_mh = upb_handlercache_get(c, subdef);
if (!sub_mh) return NULL;
upb_handlers_setsubhandlers(h, f, sub_mh);
}
}
return h;
}
upb_handlercache *upb_handlercache_new(upb_handlers_callback *callback,
const void *closure) {
upb_handlercache *cache = upb_gmalloc(sizeof(*cache));
if (!cache) return NULL;
cache->arena = upb_arena_new();
cache->callback = callback;
cache->closure = closure;
if (!upb_inttable_init(&cache->tab, UPB_CTYPE_PTR)) goto oom;
return cache;
oom:
upb_gfree(cache);
return NULL;
}
void upb_handlercache_free(upb_handlercache *cache) {
upb_inttable_uninit(&cache->tab);
upb_arena_free(cache->arena);
upb_gfree(cache);
}
bool upb_handlercache_addcleanup(upb_handlercache *c, void *p,
upb_handlerfree *func) {
return upb_arena_addcleanup(c->arena, p, func);
}
/* upb_byteshandler ***********************************************************/
bool upb_byteshandler_setstartstr(upb_byteshandler *h,
upb_startstr_handlerfunc *func, void *d) {
h->table[UPB_STARTSTR_SELECTOR].func = (upb_func*)func;
h->table[UPB_STARTSTR_SELECTOR].attr.handler_data = d;
return true;
}
bool upb_byteshandler_setstring(upb_byteshandler *h,
upb_string_handlerfunc *func, void *d) {
h->table[UPB_STRING_SELECTOR].func = (upb_func*)func;
h->table[UPB_STRING_SELECTOR].attr.handler_data = d;
return true;
}
bool upb_byteshandler_setendstr(upb_byteshandler *h,
upb_endfield_handlerfunc *func, void *d) {
h->table[UPB_ENDSTR_SELECTOR].func = (upb_func*)func;
h->table[UPB_ENDSTR_SELECTOR].attr.handler_data = d;
return true;
}
/** Handlers for upb_msg ******************************************************/
typedef struct {
size_t offset;
int32_t hasbit;
} upb_msg_handlerdata;
/* Fallback implementation if the handler is not specialized by the producer. */
#define MSG_WRITER(type, ctype) \
bool upb_msg_set ## type (void *c, const void *hd, ctype val) { \
uint8_t *m = c; \
const upb_msg_handlerdata *d = hd; \
if (d->hasbit > 0) \
*(uint8_t*)&m[d->hasbit / 8] |= 1 << (d->hasbit % 8); \
*(ctype*)&m[d->offset] = val; \
return true; \
} \
MSG_WRITER(double, double)
MSG_WRITER(float, float)
MSG_WRITER(int32, int32_t)
MSG_WRITER(int64, int64_t)
MSG_WRITER(uint32, uint32_t)
MSG_WRITER(uint64, uint64_t)
MSG_WRITER(bool, bool)
bool upb_msg_setscalarhandler(upb_handlers *h, const upb_fielddef *f,
size_t offset, int32_t hasbit) {
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
bool ok;
upb_msg_handlerdata *d = upb_gmalloc(sizeof(*d));
if (!d) return false;
d->offset = offset;
d->hasbit = hasbit;
attr.handler_data = d;
attr.alwaysok = true;
upb_handlers_addcleanup(h, d, upb_gfree);
#define TYPE(u, l) \
case UPB_TYPE_##u: \
ok = upb_handlers_set##l(h, f, upb_msg_set##l, &attr); break;
ok = false;
switch (upb_fielddef_type(f)) {
TYPE(INT64, int64);
TYPE(INT32, int32);
TYPE(ENUM, int32);
TYPE(UINT64, uint64);
TYPE(UINT32, uint32);
TYPE(DOUBLE, double);
TYPE(FLOAT, float);
TYPE(BOOL, bool);
default: UPB_ASSERT(false); break;
}
#undef TYPE
return ok;
}
bool upb_msg_getscalarhandlerdata(const upb_handlers *h,
upb_selector_t s,
upb_fieldtype_t *type,
size_t *offset,
int32_t *hasbit) {
const upb_msg_handlerdata *d;
const void *p;
upb_func *f = upb_handlers_gethandler(h, s, &p);
if ((upb_int64_handlerfunc*)f == upb_msg_setint64) {
*type = UPB_TYPE_INT64;
} else if ((upb_int32_handlerfunc*)f == upb_msg_setint32) {
*type = UPB_TYPE_INT32;
} else if ((upb_uint64_handlerfunc*)f == upb_msg_setuint64) {
*type = UPB_TYPE_UINT64;
} else if ((upb_uint32_handlerfunc*)f == upb_msg_setuint32) {
*type = UPB_TYPE_UINT32;
} else if ((upb_double_handlerfunc*)f == upb_msg_setdouble) {
*type = UPB_TYPE_DOUBLE;
} else if ((upb_float_handlerfunc*)f == upb_msg_setfloat) {
*type = UPB_TYPE_FLOAT;
} else if ((upb_bool_handlerfunc*)f == upb_msg_setbool) {
*type = UPB_TYPE_BOOL;
} else {
return false;
}
d = p;
*offset = d->offset;
*hasbit = d->hasbit;
return true;
}

@ -1,735 +0,0 @@
/*
** upb::Handlers (upb_handlers)
**
** A upb_handlers is like a virtual table for a upb_msgdef. Each field of the
** message can have associated functions that will be called when we are
** parsing or visiting a stream of data. This is similar to how handlers work
** in SAX (the Simple API for XML).
**
** The handlers have no idea where the data is coming from, so a single set of
** handlers could be used with two completely different data sources (for
** example, a parser and a visitor over in-memory objects). This decoupling is
** the most important feature of upb, because it allows parsers and serializers
** to be highly reusable.
**
** This is a mixed C/C++ interface that offers a full API to both languages.
** See the top-level README for more information.
*/
#ifndef UPB_HANDLERS_H
#define UPB_HANDLERS_H
#include "upb/def.h"
#include "upb/table.int.h"
#include "upb/port_def.inc"
#ifdef __cplusplus
#include "upb/def.hpp"
namespace upb {
class HandlersPtr;
class HandlerCache;
template <class T> class Handler;
template <class T> struct CanonicalType;
} /* namespace upb */
#endif
/* The maximum depth that the handler graph can have. This is a resource limit
* for the C stack since we sometimes need to recursively traverse the graph.
* Cycles are ok; the traversal will stop when it detects a cycle, but we must
* hit the cycle before the maximum depth is reached.
*
* If having a single static limit is too inflexible, we can add another variant
* of Handlers::Freeze that allows specifying this as a parameter. */
#define UPB_MAX_HANDLER_DEPTH 64
/* All the different types of handlers that can be registered.
* Only needed for the advanced functions in upb::Handlers. */
typedef enum {
UPB_HANDLER_INT32,
UPB_HANDLER_INT64,
UPB_HANDLER_UINT32,
UPB_HANDLER_UINT64,
UPB_HANDLER_FLOAT,
UPB_HANDLER_DOUBLE,
UPB_HANDLER_BOOL,
UPB_HANDLER_STARTSTR,
UPB_HANDLER_STRING,
UPB_HANDLER_ENDSTR,
UPB_HANDLER_STARTSUBMSG,
UPB_HANDLER_ENDSUBMSG,
UPB_HANDLER_STARTSEQ,
UPB_HANDLER_ENDSEQ
} upb_handlertype_t;
#define UPB_HANDLER_MAX (UPB_HANDLER_ENDSEQ+1)
#define UPB_BREAK NULL
/* A convenient definition for when no closure is needed. */
extern char _upb_noclosure;
#define UPB_NO_CLOSURE &_upb_noclosure
/* A selector refers to a specific field handler in the Handlers object
* (for example: the STARTSUBMSG handler for field "field15"). */
typedef int32_t upb_selector_t;
/* Static selectors for upb::Handlers. */
#define UPB_STARTMSG_SELECTOR 0
#define UPB_ENDMSG_SELECTOR 1
#define UPB_UNKNOWN_SELECTOR 2
#define UPB_STATIC_SELECTOR_COUNT 3 /* Warning: also in upb/def.c. */
/* Static selectors for upb::BytesHandler. */
#define UPB_STARTSTR_SELECTOR 0
#define UPB_STRING_SELECTOR 1
#define UPB_ENDSTR_SELECTOR 2
#ifdef __cplusplus
template<class T> const void *UniquePtrForType() {
static const char ch = 0;
return &ch;
}
#endif
/* upb_handlers ************************************************************/
/* Handler attributes, to be registered with the handler itself. */
typedef struct {
const void *handler_data;
const void *closure_type;
const void *return_closure_type;
bool alwaysok;
} upb_handlerattr;
#define UPB_HANDLERATTR_INIT {NULL, NULL, NULL, false}
/* Bufhandle, data passed along with a buffer to indicate its provenance. */
struct upb_bufhandle {
/* The beginning of the buffer. This may be different than the pointer
* passed to a StringBuf handler because the handler may receive data
* that is from the middle or end of a larger buffer. */
const char *buf;
/* The offset within the attached object where this buffer begins. Only
* meaningful if there is an attached object. */
size_t objofs;
/* The attached object (if any) and a pointer representing its type. */
const void *obj;
const void *objtype;
#ifdef __cplusplus
template <class T>
void SetAttachedObject(const T* _obj) {
obj = _obj;
objtype = UniquePtrForType<T>();
}
template <class T>
const T *GetAttachedObject() const {
return objtype == UniquePtrForType<T>() ? static_cast<const T *>(obj)
: NULL;
}
#endif
};
typedef struct upb_bufhandle upb_bufhandle;
#define UPB_BUFHANDLE_INIT {NULL, 0, NULL, NULL}
/* Handler function typedefs. */
typedef void upb_handlerfree(void *d);
typedef bool upb_unknown_handlerfunc(void *c, const void *hd, const char *buf,
size_t n);
typedef bool upb_startmsg_handlerfunc(void *c, const void*);
typedef bool upb_endmsg_handlerfunc(void *c, const void *, upb_status *status);
typedef void* upb_startfield_handlerfunc(void *c, const void *hd);
typedef bool upb_endfield_handlerfunc(void *c, const void *hd);
typedef bool upb_int32_handlerfunc(void *c, const void *hd, int32_t val);
typedef bool upb_int64_handlerfunc(void *c, const void *hd, int64_t val);
typedef bool upb_uint32_handlerfunc(void *c, const void *hd, uint32_t val);
typedef bool upb_uint64_handlerfunc(void *c, const void *hd, uint64_t val);
typedef bool upb_float_handlerfunc(void *c, const void *hd, float val);
typedef bool upb_double_handlerfunc(void *c, const void *hd, double val);
typedef bool upb_bool_handlerfunc(void *c, const void *hd, bool val);
typedef void *upb_startstr_handlerfunc(void *c, const void *hd,
size_t size_hint);
typedef size_t upb_string_handlerfunc(void *c, const void *hd, const char *buf,
size_t n, const upb_bufhandle* handle);
struct upb_handlers;
typedef struct upb_handlers upb_handlers;
#ifdef __cplusplus
extern "C" {
#endif
/* Mutating accessors. */
const upb_status *upb_handlers_status(upb_handlers *h);
void upb_handlers_clearerr(upb_handlers *h);
const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h);
bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *hfree);
bool upb_handlers_setunknown(upb_handlers *h, upb_unknown_handlerfunc *func,
const upb_handlerattr *attr);
bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func,
const upb_handlerattr *attr);
bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func,
const upb_handlerattr *attr);
bool upb_handlers_setint32(upb_handlers *h, const upb_fielddef *f,
upb_int32_handlerfunc *func,
const upb_handlerattr *attr);
bool upb_handlers_setint64(upb_handlers *h, const upb_fielddef *f,
upb_int64_handlerfunc *func,
const upb_handlerattr *attr);
bool upb_handlers_setuint32(upb_handlers *h, const upb_fielddef *f,
upb_uint32_handlerfunc *func,
const upb_handlerattr *attr);
bool upb_handlers_setuint64(upb_handlers *h, const upb_fielddef *f,
upb_uint64_handlerfunc *func,
const upb_handlerattr *attr);
bool upb_handlers_setfloat(upb_handlers *h, const upb_fielddef *f,
upb_float_handlerfunc *func,
const upb_handlerattr *attr);
bool upb_handlers_setdouble(upb_handlers *h, const upb_fielddef *f,
upb_double_handlerfunc *func,
const upb_handlerattr *attr);
bool upb_handlers_setbool(upb_handlers *h, const upb_fielddef *f,
upb_bool_handlerfunc *func,
const upb_handlerattr *attr);
bool upb_handlers_setstartstr(upb_handlers *h, const upb_fielddef *f,
upb_startstr_handlerfunc *func,
const upb_handlerattr *attr);
bool upb_handlers_setstring(upb_handlers *h, const upb_fielddef *f,
upb_string_handlerfunc *func,
const upb_handlerattr *attr);
bool upb_handlers_setendstr(upb_handlers *h, const upb_fielddef *f,
upb_endfield_handlerfunc *func,
const upb_handlerattr *attr);
bool upb_handlers_setstartseq(upb_handlers *h, const upb_fielddef *f,
upb_startfield_handlerfunc *func,
const upb_handlerattr *attr);
bool upb_handlers_setstartsubmsg(upb_handlers *h, const upb_fielddef *f,
upb_startfield_handlerfunc *func,
const upb_handlerattr *attr);
bool upb_handlers_setendsubmsg(upb_handlers *h, const upb_fielddef *f,
upb_endfield_handlerfunc *func,
const upb_handlerattr *attr);
bool upb_handlers_setendseq(upb_handlers *h, const upb_fielddef *f,
upb_endfield_handlerfunc *func,
const upb_handlerattr *attr);
/* Read-only accessors. */
const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
const upb_fielddef *f);
const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
upb_selector_t sel);
upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s,
const void **handler_data);
bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t s,
upb_handlerattr *attr);
/* "Static" methods */
upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f);
bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type,
upb_selector_t *s);
UPB_INLINE upb_selector_t upb_handlers_getendselector(upb_selector_t start) {
return start + 1;
}
#ifdef __cplusplus
} /* extern "C" */
namespace upb {
typedef upb_handlers Handlers;
}
/* Convenience macros for creating a Handler object that is wrapped with a
* type-safe wrapper function that converts the "void*" parameters/returns
* of the underlying C API into nice C++ function.
*
* Sample usage:
* void OnValue1(MyClosure* c, const MyHandlerData* d, int32_t val) {
* // do stuff ...
* }
*
* // Handler that doesn't need any data bound to it.
* void OnValue2(MyClosure* c, int32_t val) {
* // do stuff ...
* }
*
* // Handler that returns bool so it can return failure if necessary.
* bool OnValue3(MyClosure* c, int32_t val) {
* // do stuff ...
* return ok;
* }
*
* // Member function handler.
* class MyClosure {
* public:
* void OnValue(int32_t val) {
* // do stuff ...
* }
* };
*
* // Takes ownership of the MyHandlerData.
* handlers->SetInt32Handler(f1, UpbBind(OnValue1, new MyHandlerData(...)));
* handlers->SetInt32Handler(f2, UpbMakeHandler(OnValue2));
* handlers->SetInt32Handler(f1, UpbMakeHandler(OnValue3));
* handlers->SetInt32Handler(f2, UpbMakeHandler(&MyClosure::OnValue));
*/
/* In C++11, the "template" disambiguator can appear even outside templates,
* so all calls can safely use this pair of macros. */
#define UpbMakeHandler(f) upb::MatchFunc(f).template GetFunc<f>()
/* We have to be careful to only evaluate "d" once. */
#define UpbBind(f, d) upb::MatchFunc(f).template GetFunc<f>((d))
/* Handler: a struct that contains the (handler, data, deleter) tuple that is
* used to register all handlers. Users can Make() these directly but it's
* more convenient to use the UpbMakeHandler/UpbBind macros above. */
template <class T> class upb::Handler {
public:
/* The underlying, handler function signature that upb uses internally. */
typedef T FuncPtr;
/* Intentionally implicit. */
template <class F> Handler(F func);
~Handler() { UPB_ASSERT(registered_); }
void AddCleanup(upb_handlers* h) const;
FuncPtr handler() const { return handler_; }
const upb_handlerattr& attr() const { return attr_; }
private:
Handler(const Handler&) = delete;
Handler& operator=(const Handler&) = delete;
FuncPtr handler_;
mutable upb_handlerattr attr_;
mutable bool registered_;
void *cleanup_data_;
upb_handlerfree *cleanup_func_;
};
/* A upb::Handlers object represents the set of handlers associated with a
* message in the graph of messages. You can think of it as a big virtual
* table with functions corresponding to all the events that can fire while
* parsing or visiting a message of a specific type.
*
* Any handlers that are not set behave as if they had successfully consumed
* the value. Any unset Start* handlers will propagate their closure to the
* inner frame.
*
* The easiest way to create the *Handler objects needed by the Set* methods is
* with the UpbBind() and UpbMakeHandler() macros; see below. */
class upb::HandlersPtr {
public:
HandlersPtr(upb_handlers* ptr) : ptr_(ptr) {}
upb_handlers* ptr() const { return ptr_; }
typedef upb_selector_t Selector;
typedef upb_handlertype_t Type;
typedef Handler<void *(*)(void *, const void *)> StartFieldHandler;
typedef Handler<bool (*)(void *, const void *)> EndFieldHandler;
typedef Handler<bool (*)(void *, const void *)> StartMessageHandler;
typedef Handler<bool (*)(void *, const void *, upb_status *)>
EndMessageHandler;
typedef Handler<void *(*)(void *, const void *, size_t)> StartStringHandler;
typedef Handler<size_t (*)(void *, const void *, const char *, size_t,
const upb_bufhandle *)>
StringHandler;
template <class T> struct ValueHandler {
typedef Handler<bool(*)(void *, const void *, T)> H;
};
typedef ValueHandler<int32_t>::H Int32Handler;
typedef ValueHandler<int64_t>::H Int64Handler;
typedef ValueHandler<uint32_t>::H UInt32Handler;
typedef ValueHandler<uint64_t>::H UInt64Handler;
typedef ValueHandler<float>::H FloatHandler;
typedef ValueHandler<double>::H DoubleHandler;
typedef ValueHandler<bool>::H BoolHandler;
/* Any function pointer can be converted to this and converted back to its
* correct type. */
typedef void GenericFunction();
typedef void HandlersCallback(const void *closure, upb_handlers *h);
/* Returns the msgdef associated with this handlers object. */
MessageDefPtr message_def() const {
return MessageDefPtr(upb_handlers_msgdef(ptr()));
}
/* Adds the given pointer and function to the list of cleanup functions that
* will be run when these handlers are freed. If this pointer has previously
* been registered, the function returns false and does nothing. */
bool AddCleanup(void *ptr, upb_handlerfree *cleanup) {
return upb_handlers_addcleanup(ptr_, ptr, cleanup);
}
/* Sets the startmsg handler for the message, which is defined as follows:
*
* bool startmsg(MyType* closure) {
* // Called when the message begins. Returns true if processing should
* // continue.
* return true;
* }
*/
bool SetStartMessageHandler(const StartMessageHandler &h) {
h.AddCleanup(ptr());
return upb_handlers_setstartmsg(ptr(), h.handler(), &h.attr());
}
/* Sets the endmsg handler for the message, which is defined as follows:
*
* bool endmsg(MyType* closure, upb_status *status) {
* // Called when processing of this message ends, whether in success or
* // failure. "status" indicates the final status of processing, and
* // can also be modified in-place to update the final status.
* }
*/
bool SetEndMessageHandler(const EndMessageHandler& h) {
h.AddCleanup(ptr());
return upb_handlers_setendmsg(ptr(), h.handler(), &h.attr());
}
/* Sets the value handler for the given field, which is defined as follows
* (this is for an int32 field; other field types will pass their native
* C/C++ type for "val"):
*
* bool OnValue(MyClosure* c, const MyHandlerData* d, int32_t val) {
* // Called when the field's value is encountered. "d" contains
* // whatever data was bound to this field when it was registered.
* // Returns true if processing should continue.
* return true;
* }
*
* handers->SetInt32Handler(f, UpbBind(OnValue, new MyHandlerData(...)));
*
* The value type must exactly match f->type().
* For example, a handler that takes an int32_t parameter may only be used for
* fields of type UPB_TYPE_INT32 and UPB_TYPE_ENUM.
*
* Returns false if the handler failed to register; in this case the cleanup
* handler (if any) will be called immediately.
*/
bool SetInt32Handler(FieldDefPtr f, const Int32Handler &h) {
h.AddCleanup(ptr());
return upb_handlers_setint32(ptr(), f.ptr(), h.handler(), &h.attr());
}
bool SetInt64Handler (FieldDefPtr f, const Int64Handler& h) {
h.AddCleanup(ptr());
return upb_handlers_setint64(ptr(), f.ptr(), h.handler(), &h.attr());
}
bool SetUInt32Handler(FieldDefPtr f, const UInt32Handler& h) {
h.AddCleanup(ptr());
return upb_handlers_setuint32(ptr(), f.ptr(), h.handler(), &h.attr());
}
bool SetUInt64Handler(FieldDefPtr f, const UInt64Handler& h) {
h.AddCleanup(ptr());
return upb_handlers_setuint64(ptr(), f.ptr(), h.handler(), &h.attr());
}
bool SetFloatHandler (FieldDefPtr f, const FloatHandler& h) {
h.AddCleanup(ptr());
return upb_handlers_setfloat(ptr(), f.ptr(), h.handler(), &h.attr());
}
bool SetDoubleHandler(FieldDefPtr f, const DoubleHandler& h) {
h.AddCleanup(ptr());
return upb_handlers_setdouble(ptr(), f.ptr(), h.handler(), &h.attr());
}
bool SetBoolHandler(FieldDefPtr f, const BoolHandler &h) {
h.AddCleanup(ptr());
return upb_handlers_setbool(ptr(), f.ptr(), h.handler(), &h.attr());
}
/* Like the previous, but templated on the type on the value (ie. int32).
* This is mostly useful to call from other templates. To call this you must
* specify the template parameter explicitly, ie:
* h->SetValueHandler<T>(f, UpbBind(MyHandler<T>, MyData)); */
template <class T>
bool SetValueHandler(
FieldDefPtr f,
const typename ValueHandler<typename CanonicalType<T>::Type>::H &handler);
/* Sets handlers for a string field, which are defined as follows:
*
* MySubClosure* startstr(MyClosure* c, const MyHandlerData* d,
* size_t size_hint) {
* // Called when a string value begins. The return value indicates the
* // closure for the string. "size_hint" indicates the size of the
* // string if it is known, however if the string is length-delimited
* // and the end-of-string is not available size_hint will be zero.
* // This case is indistinguishable from the case where the size is
* // known to be zero.
* //
* // TODO(haberman): is it important to distinguish these cases?
* // If we had ssize_t as a type we could make -1 "unknown", but
* // ssize_t is POSIX (not ANSI) and therefore less portable.
* // In practice I suspect it won't be important to distinguish.
* return closure;
* }
*
* size_t str(MyClosure* closure, const MyHandlerData* d,
* const char *str, size_t len) {
* // Called for each buffer of string data; the multiple physical buffers
* // are all part of the same logical string. The return value indicates
* // how many bytes were consumed. If this number is less than "len",
* // this will also indicate that processing should be halted for now,
* // like returning false or UPB_BREAK from any other callback. If
* // number is greater than "len", the excess bytes will be skipped over
* // and not passed to the callback.
* return len;
* }
*
* bool endstr(MyClosure* c, const MyHandlerData* d) {
* // Called when a string value ends. Return value indicates whether
* // processing should continue.
* return true;
* }
*/
bool SetStartStringHandler(FieldDefPtr f, const StartStringHandler &h) {
h.AddCleanup(ptr());
return upb_handlers_setstartstr(ptr(), f.ptr(), h.handler(), &h.attr());
}
bool SetStringHandler(FieldDefPtr f, const StringHandler& h) {
h.AddCleanup(ptr());
return upb_handlers_setstring(ptr(), f.ptr(), h.handler(), &h.attr());
}
bool SetEndStringHandler(FieldDefPtr f, const EndFieldHandler& h) {
h.AddCleanup(ptr());
return upb_handlers_setendstr(ptr(), f.ptr(), h.handler(), &h.attr());
}
/* Sets the startseq handler, which is defined as follows:
*
* MySubClosure *startseq(MyClosure* c, const MyHandlerData* d) {
* // Called when a sequence (repeated field) begins. The returned
* // pointer indicates the closure for the sequence (or UPB_BREAK
* // to interrupt processing).
* return closure;
* }
*
* h->SetStartSequenceHandler(f, UpbBind(startseq, new MyHandlerData(...)));
*
* Returns "false" if "f" does not belong to this message or is not a
* repeated field.
*/
bool SetStartSequenceHandler(FieldDefPtr f, const StartFieldHandler &h) {
h.AddCleanup(ptr());
return upb_handlers_setstartseq(ptr(), f.ptr(), h.handler(), &h.attr());
}
/* Sets the startsubmsg handler for the given field, which is defined as
* follows:
*
* MySubClosure* startsubmsg(MyClosure* c, const MyHandlerData* d) {
* // Called when a submessage begins. The returned pointer indicates the
* // closure for the sequence (or UPB_BREAK to interrupt processing).
* return closure;
* }
*
* h->SetStartSubMessageHandler(f, UpbBind(startsubmsg,
* new MyHandlerData(...)));
*
* Returns "false" if "f" does not belong to this message or is not a
* submessage/group field.
*/
bool SetStartSubMessageHandler(FieldDefPtr f, const StartFieldHandler& h) {
h.AddCleanup(ptr());
return upb_handlers_setstartsubmsg(ptr(), f.ptr(), h.handler(), &h.attr());
}
/* Sets the endsubmsg handler for the given field, which is defined as
* follows:
*
* bool endsubmsg(MyClosure* c, const MyHandlerData* d) {
* // Called when a submessage ends. Returns true to continue processing.
* return true;
* }
*
* Returns "false" if "f" does not belong to this message or is not a
* submessage/group field.
*/
bool SetEndSubMessageHandler(FieldDefPtr f, const EndFieldHandler &h) {
h.AddCleanup(ptr());
return upb_handlers_setendsubmsg(ptr(), f.ptr(), h.handler(), &h.attr());
}
/* Starts the endsubseq handler for the given field, which is defined as
* follows:
*
* bool endseq(MyClosure* c, const MyHandlerData* d) {
* // Called when a sequence ends. Returns true continue processing.
* return true;
* }
*
* Returns "false" if "f" does not belong to this message or is not a
* repeated field.
*/
bool SetEndSequenceHandler(FieldDefPtr f, const EndFieldHandler &h) {
h.AddCleanup(ptr());
return upb_handlers_setendseq(ptr(), f.ptr(), h.handler(), &h.attr());
}
private:
upb_handlers* ptr_;
};
#endif /* __cplusplus */
/* upb_handlercache ***********************************************************/
/* A upb_handlercache lazily builds and caches upb_handlers. You pass it a
* function (with optional closure) that can build handlers for a given
* message on-demand, and the cache maintains a map of msgdef->handlers. */
#ifdef __cplusplus
extern "C" {
#endif
struct upb_handlercache;
typedef struct upb_handlercache upb_handlercache;
typedef void upb_handlers_callback(const void *closure, upb_handlers *h);
upb_handlercache *upb_handlercache_new(upb_handlers_callback *callback,
const void *closure);
void upb_handlercache_free(upb_handlercache *cache);
const upb_handlers *upb_handlercache_get(upb_handlercache *cache,
const upb_msgdef *md);
bool upb_handlercache_addcleanup(upb_handlercache *h, void *p,
upb_handlerfree *hfree);
#ifdef __cplusplus
} /* extern "C" */
class upb::HandlerCache {
public:
HandlerCache(upb_handlers_callback *callback, const void *closure)
: ptr_(upb_handlercache_new(callback, closure), upb_handlercache_free) {}
HandlerCache(HandlerCache&&) = default;
HandlerCache& operator=(HandlerCache&&) = default;
HandlerCache(upb_handlercache* c) : ptr_(c, upb_handlercache_free) {}
upb_handlercache* ptr() { return ptr_.get(); }
const upb_handlers *Get(MessageDefPtr md) {
return upb_handlercache_get(ptr_.get(), md.ptr());
}
private:
std::unique_ptr<upb_handlercache, decltype(&upb_handlercache_free)> ptr_;
};
#endif /* __cplusplus */
/* upb_byteshandler ***********************************************************/
typedef struct {
upb_func *func;
/* It is wasteful to include the entire attributes here:
*
* * Some of the information is redundant (like storing the closure type
* separately for each handler that must match).
* * Some of the info is only needed prior to freeze() (like closure types).
* * alignment padding wastes a lot of space for alwaysok_.
*
* If/when the size and locality of handlers is an issue, we can optimize this
* not to store the entire attr like this. We do not expose the table's
* layout to allow this optimization in the future. */
upb_handlerattr attr;
} upb_handlers_tabent;
#define UPB_TABENT_INIT {NULL, UPB_HANDLERATTR_INIT}
typedef struct {
upb_handlers_tabent table[3];
} upb_byteshandler;
#define UPB_BYTESHANDLER_INIT \
{ \
{ UPB_TABENT_INIT, UPB_TABENT_INIT, UPB_TABENT_INIT } \
}
UPB_INLINE void upb_byteshandler_init(upb_byteshandler *handler) {
upb_byteshandler init = UPB_BYTESHANDLER_INIT;
*handler = init;
}
#ifdef __cplusplus
extern "C" {
#endif
/* Caller must ensure that "d" outlives the handlers. */
bool upb_byteshandler_setstartstr(upb_byteshandler *h,
upb_startstr_handlerfunc *func, void *d);
bool upb_byteshandler_setstring(upb_byteshandler *h,
upb_string_handlerfunc *func, void *d);
bool upb_byteshandler_setendstr(upb_byteshandler *h,
upb_endfield_handlerfunc *func, void *d);
#ifdef __cplusplus
} /* extern "C" */
namespace upb {
typedef upb_byteshandler BytesHandler;
}
#endif
/** Message handlers ******************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
/* These are the handlers used internally by upb_msgfactory_getmergehandlers().
* They write scalar data to a known offset from the message pointer.
*
* These would be trivial for anyone to implement themselves, but it's better
* to use these because some JITs will recognize and specialize these instead
* of actually calling the function. */
/* Sets a handler for the given primitive field that will write the data at the
* given offset. If hasbit > 0, also sets a hasbit at the given bit offset
* (addressing each byte low to high). */
bool upb_msg_setscalarhandler(upb_handlers *h,
const upb_fielddef *f,
size_t offset,
int32_t hasbit);
/* If the given handler is a msghandlers_primitive field, returns true and sets
* *type, *offset and *hasbit. Otherwise returns false. */
bool upb_msg_getscalarhandlerdata(const upb_handlers *h,
upb_selector_t s,
upb_fieldtype_t *type,
size_t *offset,
int32_t *hasbit);
#ifdef __cplusplus
} /* extern "C" */
#endif
#include "upb/port_undef.inc"
#include "upb/handlers-inl.h"
#endif /* UPB_HANDLERS_H */

@ -1,140 +0,0 @@
/*
** upb::json::Parser (upb_json_parser)
**
** Parses JSON according to a specific schema.
** Support for parsing arbitrary JSON (schema-less) will be added later.
*/
#ifndef UPB_JSON_PARSER_H_
#define UPB_JSON_PARSER_H_
#include "upb/sink.h"
#ifdef __cplusplus
namespace upb {
namespace json {
class CodeCache;
class ParserPtr;
class ParserMethodPtr;
} /* namespace json */
} /* namespace upb */
#endif
/* upb_json_parsermethod ******************************************************/
struct upb_json_parsermethod;
typedef struct upb_json_parsermethod upb_json_parsermethod;
#ifdef __cplusplus
extern "C" {
#endif
const upb_byteshandler* upb_json_parsermethod_inputhandler(
const upb_json_parsermethod* m);
#ifdef __cplusplus
} /* extern "C" */
class upb::json::ParserMethodPtr {
public:
ParserMethodPtr() : ptr_(nullptr) {}
ParserMethodPtr(const upb_json_parsermethod* ptr) : ptr_(ptr) {}
const upb_json_parsermethod* ptr() const { return ptr_; }
const BytesHandler* input_handler() const {
return upb_json_parsermethod_inputhandler(ptr());
}
private:
const upb_json_parsermethod* ptr_;
};
#endif /* __cplusplus */
/* upb_json_parser ************************************************************/
/* Preallocation hint: parser won't allocate more bytes than this when first
* constructed. This hint may be an overestimate for some build configurations.
* But if the parser library is upgraded without recompiling the application,
* it may be an underestimate. */
#define UPB_JSON_PARSER_SIZE 5712
struct upb_json_parser;
typedef struct upb_json_parser upb_json_parser;
#ifdef __cplusplus
extern "C" {
#endif
upb_json_parser* upb_json_parser_create(upb_arena* a,
const upb_json_parsermethod* m,
const upb_symtab* symtab,
upb_sink output,
upb_status *status,
bool ignore_json_unknown);
upb_bytessink upb_json_parser_input(upb_json_parser* p);
#ifdef __cplusplus
} /* extern "C" */
/* Parses an incoming BytesStream, pushing the results to the destination
* sink. */
class upb::json::ParserPtr {
public:
ParserPtr(upb_json_parser* ptr) : ptr_(ptr) {}
static ParserPtr Create(Arena* arena, ParserMethodPtr method,
SymbolTable* symtab, Sink output, Status* status,
bool ignore_json_unknown) {
upb_symtab* symtab_ptr = symtab ? symtab->ptr() : nullptr;
return ParserPtr(upb_json_parser_create(
arena->ptr(), method.ptr(), symtab_ptr, output.sink(), status->ptr(),
ignore_json_unknown));
}
BytesSink input() { return upb_json_parser_input(ptr_); }
private:
upb_json_parser* ptr_;
};
#endif /* __cplusplus */
/* upb_json_codecache *********************************************************/
/* Lazily builds and caches decoder methods that will push data to the given
* handlers. The upb_symtab object(s) must outlive this object. */
struct upb_json_codecache;
typedef struct upb_json_codecache upb_json_codecache;
#ifdef __cplusplus
extern "C" {
#endif
upb_json_codecache *upb_json_codecache_new(void);
void upb_json_codecache_free(upb_json_codecache *cache);
const upb_json_parsermethod* upb_json_codecache_get(upb_json_codecache* cache,
const upb_msgdef* md);
#ifdef __cplusplus
} /* extern "C" */
class upb::json::CodeCache {
public:
CodeCache() : ptr_(upb_json_codecache_new(), upb_json_codecache_free) {}
/* Returns a DecoderMethod that can push data to the given handlers.
* If a suitable method already exists, it will be returned from the cache. */
ParserMethodPtr Get(MessageDefPtr md) {
return upb_json_codecache_get(ptr_.get(), md.ptr());
}
private:
std::unique_ptr<upb_json_codecache, decltype(&upb_json_codecache_free)> ptr_;
};
#endif
#endif /* UPB_JSON_PARSER_H_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,72 +0,0 @@
/*
** upb::json::Printer
**
** Handlers that emit JSON according to a specific protobuf schema.
*/
#ifndef UPB_JSON_TYPED_PRINTER_H_
#define UPB_JSON_TYPED_PRINTER_H_
#include "upb/sink.h"
#ifdef __cplusplus
namespace upb {
namespace json {
class PrinterPtr;
} /* namespace json */
} /* namespace upb */
#endif
/* upb_json_printer ***********************************************************/
#define UPB_JSON_PRINTER_SIZE 192
struct upb_json_printer;
typedef struct upb_json_printer upb_json_printer;
#ifdef __cplusplus
extern "C" {
#endif
/* Native C API. */
upb_json_printer *upb_json_printer_create(upb_arena *a, const upb_handlers *h,
upb_bytessink output);
upb_sink upb_json_printer_input(upb_json_printer *p);
const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md,
bool preserve_fieldnames,
const void *owner);
/* Lazily builds and caches handlers that will push encoded data to a bytessink.
* Any msgdef objects used with this object must outlive it. */
upb_handlercache *upb_json_printer_newcache(bool preserve_proto_fieldnames);
#ifdef __cplusplus
} /* extern "C" */
/* Prints an incoming stream of data to a BytesSink in JSON format. */
class upb::json::PrinterPtr {
public:
PrinterPtr(upb_json_printer* ptr) : ptr_(ptr) {}
static PrinterPtr Create(Arena *arena, const upb::Handlers *handlers,
BytesSink output) {
return PrinterPtr(
upb_json_printer_create(arena->ptr(), handlers, output.sink()));
}
/* The input to the printer. */
Sink input() { return upb_json_printer_input(ptr_); }
static const size_t kSize = UPB_JSON_PRINTER_SIZE;
static HandlerCache NewCache(bool preserve_proto_fieldnames) {
return upb_json_printer_newcache(preserve_proto_fieldnames);
}
private:
upb_json_printer* ptr_;
};
#endif /* __cplusplus */
#endif /* UPB_JSON_TYPED_PRINTER_H_ */

@ -62,6 +62,7 @@ UPB_NORETURN static void jsondec_err(jsondec *d, const char *msg) {
UPB_LONGJMP(d->err, 1);
}
UPB_PRINTF(2, 3)
UPB_NORETURN static void jsondec_errf(jsondec *d, const char *fmt, ...) {
va_list argp;
upb_status_seterrf(d->status, "Error parsing JSON @%d:%d: ", d->line,
@ -678,7 +679,7 @@ static upb_msgval jsondec_int(jsondec *d, const upb_fielddef *f) {
}
val.int64_val = dbl; /* must be guarded, overflow here is UB */
if (val.int64_val != dbl) {
jsondec_errf(d, "JSON number was not integral (%d != %" PRId64 ")", dbl,
jsondec_errf(d, "JSON number was not integral (%f != %" PRId64 ")", dbl,
val.int64_val);
}
break;
@ -704,7 +705,7 @@ static upb_msgval jsondec_int(jsondec *d, const upb_fielddef *f) {
/* Parse UINT32 or UINT64 value. */
static upb_msgval jsondec_uint(jsondec *d, const upb_fielddef *f) {
upb_msgval val;
upb_msgval val = {0};
switch (jsondec_peek(d)) {
case JD_NUMBER: {
@ -714,7 +715,7 @@ static upb_msgval jsondec_uint(jsondec *d, const upb_fielddef *f) {
}
val.uint64_val = dbl; /* must be guarded, overflow here is UB */
if (val.uint64_val != dbl) {
jsondec_errf(d, "JSON number was not integral (%d != %" PRIu64 ")", dbl,
jsondec_errf(d, "JSON number was not integral (%f != %" PRIu64 ")", dbl,
val.uint64_val);
}
break;
@ -741,7 +742,7 @@ static upb_msgval jsondec_uint(jsondec *d, const upb_fielddef *f) {
/* Parse DOUBLE or FLOAT value. */
static upb_msgval jsondec_double(jsondec *d, const upb_fielddef *f) {
upb_strview str;
upb_msgval val;
upb_msgval val = {0};
switch (jsondec_peek(d)) {
case JD_NUMBER:
@ -905,7 +906,7 @@ static void jsondec_field(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
if (!f) {
if ((d->options & UPB_JSONDEC_IGNOREUNKNOWN) == 0) {
jsondec_errf(d, "Unknown field: '" UPB_STRVIEW_FORMAT "'",
jsondec_errf(d, "No such field: " UPB_STRVIEW_FORMAT,
UPB_STRVIEW_ARGS(name));
}
jsondec_skipval(d);
@ -1058,7 +1059,8 @@ static void jsondec_timestamp(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
{
/* [+-]08:00 or Z */
int ofs = 0;
int ofs_hour = 0;
int ofs_min = 0;
bool neg = false;
if (ptr == end) goto malformed;
@ -1069,9 +1071,10 @@ static void jsondec_timestamp(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
/* fallthrough */
case '+':
if ((end - ptr) != 5) goto malformed;
ofs = jsondec_tsdigits(d, &ptr, 2, ":00");
ofs *= 60 * 60;
seconds.int64_val += (neg ? ofs : -ofs);
ofs_hour = jsondec_tsdigits(d, &ptr, 2, ":");
ofs_min = jsondec_tsdigits(d, &ptr, 2, NULL);
ofs_min = ((ofs_hour * 60) + ofs_min) * 60;
seconds.int64_val += (neg ? ofs_min : -ofs_min);
break;
case 'Z':
if (ptr != end) goto malformed;

@ -32,7 +32,7 @@ static void jsonenc_scalar(jsonenc *e, upb_msgval val, const upb_fielddef *f);
static void jsonenc_msgfield(jsonenc *e, const upb_msg *msg,
const upb_msgdef *m);
static void jsonenc_msgfields(jsonenc *e, const upb_msg *msg,
const upb_msgdef *m);
const upb_msgdef *m, bool first);
static void jsonenc_value(jsonenc *e, const upb_msg *msg, const upb_msgdef *m);
UPB_NORETURN static void jsonenc_err(jsonenc *e, const char *msg) {
@ -40,6 +40,7 @@ UPB_NORETURN static void jsonenc_err(jsonenc *e, const char *msg) {
longjmp(e->err, 1);
}
UPB_PRINTF(2, 3)
UPB_NORETURN static void jsonenc_errf(jsonenc *e, const char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
@ -72,6 +73,7 @@ static void jsonenc_putstr(jsonenc *e, const char *str) {
jsonenc_putbytes(e, str, strlen(str));
}
UPB_PRINTF(2, 3)
static void jsonenc_printf(jsonenc *e, const char *fmt, ...) {
size_t n;
size_t have = e->end - e->ptr;
@ -102,7 +104,7 @@ static void jsonenc_nanos(jsonenc *e, int32_t nanos) {
digits -= 3;
}
jsonenc_printf(e, ".%0.*" PRId32, digits, nanos);
jsonenc_printf(e, ".%.*" PRId32, digits, nanos);
}
static void jsonenc_timestamp(jsonenc *e, const upb_msg *msg,
@ -340,14 +342,13 @@ static void jsonenc_any(jsonenc *e, const upb_msg *msg, const upb_msgdef *m) {
jsonenc_putstr(e, "{\"@type\":");
jsonenc_string(e, type_url);
jsonenc_putstr(e, ",");
if (upb_msgdef_wellknowntype(any_m) == UPB_WELLKNOWN_UNSPECIFIED) {
/* Regular messages: {"@type": "...","foo": 1, "bar": 2} */
jsonenc_msgfields(e, any, any_m);
jsonenc_msgfields(e, any, any_m, false);
} else {
/* Well-known type: {"@type": "...","value": <well-known encoding>} */
jsonenc_putstr(e, "\"value\":");
jsonenc_putstr(e, ",\"value\":");
jsonenc_msgfield(e, any, any_m);
}
@ -594,7 +595,7 @@ static void jsonenc_mapkey(jsonenc *e, upb_msgval val, const upb_fielddef *f) {
static void jsonenc_array(jsonenc *e, const upb_array *arr,
const upb_fielddef *f) {
size_t i;
size_t size = upb_array_size(arr);
size_t size = arr ? upb_array_size(arr) : 0;
bool first = true;
jsonenc_putstr(e, "[");
@ -616,10 +617,12 @@ static void jsonenc_map(jsonenc *e, const upb_map *map, const upb_fielddef *f) {
jsonenc_putstr(e, "{");
while (upb_mapiter_next(map, &iter)) {
jsonenc_putsep(e, ",", &first);
jsonenc_mapkey(e, upb_mapiter_key(map, iter), key_f);
jsonenc_scalar(e, upb_mapiter_value(map, iter), val_f);
if (map) {
while (upb_mapiter_next(map, &iter)) {
jsonenc_putsep(e, ",", &first);
jsonenc_mapkey(e, upb_mapiter_key(map, iter), key_f);
jsonenc_scalar(e, upb_mapiter_value(map, iter), val_f);
}
}
jsonenc_putstr(e, "}");
@ -648,10 +651,9 @@ static void jsonenc_fieldval(jsonenc *e, const upb_fielddef *f,
}
static void jsonenc_msgfields(jsonenc *e, const upb_msg *msg,
const upb_msgdef *m) {
const upb_msgdef *m, bool first) {
upb_msgval val;
const upb_fielddef *f;
bool first = true;
if (e->options & UPB_JSONENC_EMITDEFAULTS) {
/* Iterate over all fields. */
@ -659,7 +661,9 @@ static void jsonenc_msgfields(jsonenc *e, const upb_msg *msg,
int n = upb_msgdef_fieldcount(m);
for (i = 0; i < n; i++) {
f = upb_msgdef_field(m, i);
jsonenc_fieldval(e, f, upb_msg_get(msg, f), &first);
if (!upb_fielddef_haspresence(f) || upb_msg_has(msg, f)) {
jsonenc_fieldval(e, f, upb_msg_get(msg, f), &first);
}
}
} else {
/* Iterate over non-empty fields. */
@ -672,7 +676,7 @@ static void jsonenc_msgfields(jsonenc *e, const upb_msg *msg,
static void jsonenc_msg(jsonenc *e, const upb_msg *msg, const upb_msgdef *m) {
jsonenc_putstr(e, "{");
jsonenc_msgfields(e, msg, m);
jsonenc_msgfields(e, msg, m, true);
jsonenc_putstr(e, "}");
}

@ -133,9 +133,124 @@ upb_map *_upb_map_new(upb_arena *a, size_t key_size, size_t value_size) {
return NULL;
}
upb_strtable_init2(&map->table, UPB_CTYPE_INT32, 4, upb_arena_alloc(a));
upb_strtable_init(&map->table, 4, a);
map->key_size = key_size;
map->val_size = value_size;
return map;
}
static void _upb_mapsorter_getkeys(const void *_a, const void *_b, void *a_key,
void *b_key, size_t size) {
const upb_tabent *const*a = _a;
const upb_tabent *const*b = _b;
upb_strview a_tabkey = upb_tabstrview((*a)->key);
upb_strview b_tabkey = upb_tabstrview((*b)->key);
_upb_map_fromkey(a_tabkey, a_key, size);
_upb_map_fromkey(b_tabkey, b_key, size);
}
static int _upb_mapsorter_cmpi64(const void *_a, const void *_b) {
int64_t a, b;
_upb_mapsorter_getkeys(_a, _b, &a, &b, 8);
return a - b;
}
static int _upb_mapsorter_cmpu64(const void *_a, const void *_b) {
uint64_t a, b;
_upb_mapsorter_getkeys(_a, _b, &a, &b, 8);
return a - b;
}
static int _upb_mapsorter_cmpi32(const void *_a, const void *_b) {
int32_t a, b;
_upb_mapsorter_getkeys(_a, _b, &a, &b, 4);
return a - b;
}
static int _upb_mapsorter_cmpu32(const void *_a, const void *_b) {
uint32_t a, b;
_upb_mapsorter_getkeys(_a, _b, &a, &b, 4);
return a - b;
}
static int _upb_mapsorter_cmpbool(const void *_a, const void *_b) {
bool a, b;
_upb_mapsorter_getkeys(_a, _b, &a, &b, 1);
return a - b;
}
static int _upb_mapsorter_cmpstr(const void *_a, const void *_b) {
upb_strview a, b;
_upb_mapsorter_getkeys(_a, _b, &a, &b, UPB_MAPTYPE_STRING);
size_t common_size = UPB_MIN(a.size, b.size);
int cmp = memcmp(a.data, b.data, common_size);
if (cmp) return cmp;
return a.size - b.size;
}
bool _upb_mapsorter_pushmap(_upb_mapsorter *s, upb_descriptortype_t key_type,
const upb_map *map, _upb_sortedmap *sorted) {
int map_size = _upb_map_size(map);
sorted->start = s->size;
sorted->pos = sorted->start;
sorted->end = sorted->start + map_size;
/* Grow s->entries if necessary. */
if (sorted->end > s->cap) {
s->cap = _upb_lg2ceilsize(sorted->end);
s->entries = realloc(s->entries, s->cap * sizeof(*s->entries));
if (!s->entries) return false;
}
s->size = sorted->end;
/* Copy non-empty entries from the table to s->entries. */
upb_tabent const**dst = &s->entries[sorted->start];
const upb_tabent *src = map->table.t.entries;
const upb_tabent *end = src + upb_table_size(&map->table.t);
for (; src < end; src++) {
if (!upb_tabent_isempty(src)) {
*dst = src;
dst++;
}
}
UPB_ASSERT(dst == &s->entries[sorted->end]);
/* Sort entries according to the key type. */
int (*compar)(const void *, const void *);
switch (key_type) {
case UPB_DESCRIPTOR_TYPE_INT64:
case UPB_DESCRIPTOR_TYPE_SFIXED64:
case UPB_DESCRIPTOR_TYPE_SINT64:
compar = _upb_mapsorter_cmpi64;
break;
case UPB_DESCRIPTOR_TYPE_UINT64:
case UPB_DESCRIPTOR_TYPE_FIXED64:
compar = _upb_mapsorter_cmpu64;
break;
case UPB_DESCRIPTOR_TYPE_INT32:
case UPB_DESCRIPTOR_TYPE_SINT32:
case UPB_DESCRIPTOR_TYPE_SFIXED32:
case UPB_DESCRIPTOR_TYPE_ENUM:
compar = _upb_mapsorter_cmpi32;
break;
case UPB_DESCRIPTOR_TYPE_UINT32:
case UPB_DESCRIPTOR_TYPE_FIXED32:
compar = _upb_mapsorter_cmpu32;
break;
case UPB_DESCRIPTOR_TYPE_BOOL:
compar = _upb_mapsorter_cmpbool;
break;
case UPB_DESCRIPTOR_TYPE_STRING:
compar = _upb_mapsorter_cmpstr;
break;
default:
UPB_UNREACHABLE();
}
qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), compar);
return true;
}

@ -9,11 +9,13 @@
#define UPB_MSG_H_
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "upb/table.int.h"
#include "upb/upb.h"
/* Must be last. */
#include "upb/port_def.inc"
#ifdef __cplusplus
@ -458,20 +460,19 @@ UPB_INLINE void* _upb_map_next(const upb_map *map, size_t *iter) {
}
UPB_INLINE bool _upb_map_set(upb_map *map, const void *key, size_t key_size,
void *val, size_t val_size, upb_arena *arena) {
void *val, size_t val_size, upb_arena *a) {
upb_strview strkey = _upb_map_tokey(key, key_size);
upb_value tabval = {0};
if (!_upb_map_tovalue(val, val_size, &tabval, arena)) return false;
upb_alloc *a = upb_arena_alloc(arena);
if (!_upb_map_tovalue(val, val_size, &tabval, a)) return false;
/* TODO(haberman): add overwrite operation to minimize number of lookups. */
upb_strtable_remove3(&map->table, strkey.data, strkey.size, NULL, a);
return upb_strtable_insert3(&map->table, strkey.data, strkey.size, tabval, a);
upb_strtable_remove(&map->table, strkey.data, strkey.size, NULL);
return upb_strtable_insert(&map->table, strkey.data, strkey.size, tabval, a);
}
UPB_INLINE bool _upb_map_delete(upb_map *map, const void *key, size_t key_size) {
upb_strview k = _upb_map_tokey(key, key_size);
return upb_strtable_remove3(&map->table, k.data, k.size, NULL, NULL);
return upb_strtable_remove(&map->table, k.data, k.size, NULL);
}
UPB_INLINE void _upb_map_clear(upb_map *map) {
@ -536,8 +537,7 @@ UPB_INLINE void _upb_msg_map_key(const void* msg, void* key, size_t size) {
UPB_INLINE void _upb_msg_map_value(const void* msg, void* val, size_t size) {
const upb_tabent *ent = (const upb_tabent*)msg;
upb_value v;
_upb_value_setval(&v, ent->val.val);
upb_value v = {ent->val.val};
_upb_map_fromvalue(v, val, size);
}
@ -553,6 +553,53 @@ UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, size_t size)
}
}
/** _upb_mapsorter *************************************************************/
/* _upb_mapsorter sorts maps and provides ordered iteration over the entries.
* Since maps can be recursive (map values can be messages which contain other maps).
* _upb_mapsorter can contain a stack of maps. */
typedef struct {
upb_tabent const**entries;
int size;
int cap;
} _upb_mapsorter;
typedef struct {
int start;
int pos;
int end;
} _upb_sortedmap;
UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter *s) {
s->entries = NULL;
s->size = 0;
s->cap = 0;
}
UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter *s) {
if (s->entries) free(s->entries);
}
bool _upb_mapsorter_pushmap(_upb_mapsorter *s, upb_descriptortype_t key_type,
const upb_map *map, _upb_sortedmap *sorted);
UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter *s, _upb_sortedmap *sorted) {
s->size = sorted->start;
}
UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter *s, const upb_map *map,
_upb_sortedmap *sorted,
upb_map_entry *ent) {
if (sorted->pos == sorted->end) return false;
const upb_tabent *tabent = s->entries[sorted->pos++];
upb_strview key = upb_tabstrview(tabent->key);
_upb_map_fromkey(key, &ent->k, map->key_size);
upb_value val = {tabent->val.val};
_upb_map_fromvalue(val, &ent->v, map->val_size);
return true;
}
#undef PTR_AT
#ifdef __cplusplus

@ -1,919 +0,0 @@
/*
** protobuf decoder bytecode compiler
**
** Code to compile a upb::Handlers into bytecode for decoding a protobuf
** according to that specific schema and destination handlers.
**
** Bytecode definition is in decoder.int.h.
*/
#include <stdarg.h>
#include "upb/pb/decoder.int.h"
#include "upb/pb/varint.int.h"
#ifdef UPB_DUMP_BYTECODE
#include <stdio.h>
#endif
#include "upb/port_def.inc"
#define MAXLABEL 5
#define EMPTYLABEL -1
/* upb_pbdecodermethod ********************************************************/
static void freemethod(upb_pbdecodermethod *method) {
upb_inttable_uninit(&method->dispatch);
upb_gfree(method);
}
static upb_pbdecodermethod *newmethod(const upb_handlers *dest_handlers,
mgroup *group) {
upb_pbdecodermethod *ret = upb_gmalloc(sizeof(*ret));
upb_byteshandler_init(&ret->input_handler_);
ret->group = group;
ret->dest_handlers_ = dest_handlers;
upb_inttable_init(&ret->dispatch, UPB_CTYPE_UINT64);
return ret;
}
const upb_handlers *upb_pbdecodermethod_desthandlers(
const upb_pbdecodermethod *m) {
return m->dest_handlers_;
}
const upb_byteshandler *upb_pbdecodermethod_inputhandler(
const upb_pbdecodermethod *m) {
return &m->input_handler_;
}
bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m) {
return m->is_native_;
}
/* mgroup *********************************************************************/
static void freegroup(mgroup *g) {
upb_inttable_iter i;
upb_inttable_begin(&i, &g->methods);
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
freemethod(upb_value_getptr(upb_inttable_iter_value(&i)));
}
upb_inttable_uninit(&g->methods);
upb_gfree(g->bytecode);
upb_gfree(g);
}
mgroup *newgroup(void) {
mgroup *g = upb_gmalloc(sizeof(*g));
upb_inttable_init(&g->methods, UPB_CTYPE_PTR);
g->bytecode = NULL;
g->bytecode_end = NULL;
return g;
}
/* bytecode compiler **********************************************************/
/* Data used only at compilation time. */
typedef struct {
mgroup *group;
uint32_t *pc;
int fwd_labels[MAXLABEL];
int back_labels[MAXLABEL];
/* For fields marked "lazy", parse them lazily or eagerly? */
bool lazy;
} compiler;
static compiler *newcompiler(mgroup *group, bool lazy) {
compiler *ret = upb_gmalloc(sizeof(*ret));
int i;
ret->group = group;
ret->lazy = lazy;
for (i = 0; i < MAXLABEL; i++) {
ret->fwd_labels[i] = EMPTYLABEL;
ret->back_labels[i] = EMPTYLABEL;
}
return ret;
}
static void freecompiler(compiler *c) {
upb_gfree(c);
}
const size_t ptr_words = sizeof(void*) / sizeof(uint32_t);
/* How many words an instruction is. */
static int instruction_len(uint32_t instr) {
switch (getop(instr)) {
case OP_SETDISPATCH: return 1 + ptr_words;
case OP_TAGN: return 3;
case OP_SETBIGGROUPNUM: return 2;
default: return 1;
}
}
bool op_has_longofs(int32_t instruction) {
switch (getop(instruction)) {
case OP_CALL:
case OP_BRANCH:
case OP_CHECKDELIM:
return true;
/* The "tag" instructions only have 8 bytes available for the jump target,
* but that is ok because these opcodes only require short jumps. */
case OP_TAG1:
case OP_TAG2:
case OP_TAGN:
return false;
default:
UPB_ASSERT(false);
return false;
}
}
static int32_t getofs(uint32_t instruction) {
if (op_has_longofs(instruction)) {
return (int32_t)instruction >> 8;
} else {
return (int8_t)(instruction >> 8);
}
}
static void setofs(uint32_t *instruction, int32_t ofs) {
if (op_has_longofs(*instruction)) {
*instruction = getop(*instruction) | (uint32_t)ofs << 8;
} else {
*instruction = (*instruction & ~0xff00) | ((ofs & 0xff) << 8);
}
UPB_ASSERT(getofs(*instruction) == ofs); /* Would fail in cases of overflow. */
}
static uint32_t pcofs(compiler *c) {
return (uint32_t)(c->pc - c->group->bytecode);
}
/* Defines a local label at the current PC location. All previous forward
* references are updated to point to this location. The location is noted
* for any future backward references. */
static void label(compiler *c, unsigned int label) {
int val;
uint32_t *codep;
UPB_ASSERT(label < MAXLABEL);
val = c->fwd_labels[label];
codep = (val == EMPTYLABEL) ? NULL : c->group->bytecode + val;
while (codep) {
int ofs = getofs(*codep);
setofs(codep, (int32_t)(c->pc - codep - instruction_len(*codep)));
codep = ofs ? codep + ofs : NULL;
}
c->fwd_labels[label] = EMPTYLABEL;
c->back_labels[label] = pcofs(c);
}
/* Creates a reference to a numbered label; either a forward reference
* (positive arg) or backward reference (negative arg). For forward references
* the value returned now is actually a "next" pointer into a linked list of all
* instructions that use this label and will be patched later when the label is
* defined with label().
*
* The returned value is the offset that should be written into the instruction.
*/
static int32_t labelref(compiler *c, int label) {
UPB_ASSERT(label < MAXLABEL);
if (label == LABEL_DISPATCH) {
/* No resolving required. */
return 0;
} else if (label < 0) {
/* Backward local label. Relative to the next instruction. */
uint32_t from = (uint32_t)((c->pc + 1) - c->group->bytecode);
return c->back_labels[-label] - from;
} else {
/* Forward local label: prepend to (possibly-empty) linked list. */
int *lptr = &c->fwd_labels[label];
int32_t ret = (*lptr == EMPTYLABEL) ? 0 : *lptr - pcofs(c);
*lptr = pcofs(c);
return ret;
}
}
static void put32(compiler *c, uint32_t v) {
mgroup *g = c->group;
if (c->pc == g->bytecode_end) {
int ofs = pcofs(c);
size_t oldsize = g->bytecode_end - g->bytecode;
size_t newsize = UPB_MAX(oldsize * 2, 64);
/* TODO(haberman): handle OOM. */
g->bytecode = upb_grealloc(g->bytecode, oldsize * sizeof(uint32_t),
newsize * sizeof(uint32_t));
g->bytecode_end = g->bytecode + newsize;
c->pc = g->bytecode + ofs;
}
*c->pc++ = v;
}
static void putop(compiler *c, int op, ...) {
va_list ap;
va_start(ap, op);
switch (op) {
case OP_SETDISPATCH: {
uintptr_t ptr = (uintptr_t)va_arg(ap, void*);
put32(c, OP_SETDISPATCH);
put32(c, (uint32_t)ptr);
if (sizeof(uintptr_t) > sizeof(uint32_t))
put32(c, (uint64_t)ptr >> 32);
break;
}
case OP_STARTMSG:
case OP_ENDMSG:
case OP_PUSHLENDELIM:
case OP_POP:
case OP_SETDELIM:
case OP_HALT:
case OP_RET:
case OP_DISPATCH:
put32(c, op);
break;
case OP_PARSE_DOUBLE:
case OP_PARSE_FLOAT:
case OP_PARSE_INT64:
case OP_PARSE_UINT64:
case OP_PARSE_INT32:
case OP_PARSE_FIXED64:
case OP_PARSE_FIXED32:
case OP_PARSE_BOOL:
case OP_PARSE_UINT32:
case OP_PARSE_SFIXED32:
case OP_PARSE_SFIXED64:
case OP_PARSE_SINT32:
case OP_PARSE_SINT64:
case OP_STARTSEQ:
case OP_ENDSEQ:
case OP_STARTSUBMSG:
case OP_ENDSUBMSG:
case OP_STARTSTR:
case OP_STRING:
case OP_ENDSTR:
case OP_PUSHTAGDELIM:
put32(c, op | va_arg(ap, upb_selector_t) << 8);
break;
case OP_SETBIGGROUPNUM:
put32(c, op);
put32(c, va_arg(ap, int));
break;
case OP_CALL: {
const upb_pbdecodermethod *method = va_arg(ap, upb_pbdecodermethod *);
put32(c, op | (method->code_base.ofs - (pcofs(c) + 1)) << 8);
break;
}
case OP_CHECKDELIM:
case OP_BRANCH: {
uint32_t instruction = op;
int label = va_arg(ap, int);
setofs(&instruction, labelref(c, label));
put32(c, instruction);
break;
}
case OP_TAG1:
case OP_TAG2: {
int label = va_arg(ap, int);
uint64_t tag = va_arg(ap, uint64_t);
uint32_t instruction = (uint32_t)(op | (tag << 16));
UPB_ASSERT(tag <= 0xffff);
setofs(&instruction, labelref(c, label));
put32(c, instruction);
break;
}
case OP_TAGN: {
int label = va_arg(ap, int);
uint64_t tag = va_arg(ap, uint64_t);
uint32_t instruction = op | (upb_value_size(tag) << 16);
setofs(&instruction, labelref(c, label));
put32(c, instruction);
put32(c, (uint32_t)tag);
put32(c, tag >> 32);
break;
}
}
va_end(ap);
}
#if defined(UPB_DUMP_BYTECODE)
const char *upb_pbdecoder_getopname(unsigned int op) {
#define QUOTE(x) #x
#define EXPAND_AND_QUOTE(x) QUOTE(x)
#define OPNAME(x) OP_##x
#define OP(x) case OPNAME(x): return EXPAND_AND_QUOTE(OPNAME(x));
#define T(x) OP(PARSE_##x)
/* Keep in sync with list in decoder.int.h. */
switch ((opcode)op) {
T(DOUBLE) T(FLOAT) T(INT64) T(UINT64) T(INT32) T(FIXED64) T(FIXED32)
T(BOOL) T(UINT32) T(SFIXED32) T(SFIXED64) T(SINT32) T(SINT64)
OP(STARTMSG) OP(ENDMSG) OP(STARTSEQ) OP(ENDSEQ) OP(STARTSUBMSG)
OP(ENDSUBMSG) OP(STARTSTR) OP(STRING) OP(ENDSTR) OP(CALL) OP(RET)
OP(PUSHLENDELIM) OP(PUSHTAGDELIM) OP(SETDELIM) OP(CHECKDELIM)
OP(BRANCH) OP(TAG1) OP(TAG2) OP(TAGN) OP(SETDISPATCH) OP(POP)
OP(SETBIGGROUPNUM) OP(DISPATCH) OP(HALT)
}
return "<unknown op>";
#undef OP
#undef T
}
#endif
#ifdef UPB_DUMP_BYTECODE
static void dumpbc(uint32_t *p, uint32_t *end, FILE *f) {
uint32_t *begin = p;
while (p < end) {
fprintf(f, "%p %8tx", p, p - begin);
uint32_t instr = *p++;
uint8_t op = getop(instr);
fprintf(f, " %s", upb_pbdecoder_getopname(op));
switch ((opcode)op) {
case OP_SETDISPATCH: {
const upb_inttable *dispatch;
memcpy(&dispatch, p, sizeof(void*));
p += ptr_words;
const upb_pbdecodermethod *method =
(void *)((char *)dispatch -
offsetof(upb_pbdecodermethod, dispatch));
fprintf(f, " %s", upb_msgdef_fullname(
upb_handlers_msgdef(method->dest_handlers_)));
break;
}
case OP_DISPATCH:
case OP_STARTMSG:
case OP_ENDMSG:
case OP_PUSHLENDELIM:
case OP_POP:
case OP_SETDELIM:
case OP_HALT:
case OP_RET:
break;
case OP_PARSE_DOUBLE:
case OP_PARSE_FLOAT:
case OP_PARSE_INT64:
case OP_PARSE_UINT64:
case OP_PARSE_INT32:
case OP_PARSE_FIXED64:
case OP_PARSE_FIXED32:
case OP_PARSE_BOOL:
case OP_PARSE_UINT32:
case OP_PARSE_SFIXED32:
case OP_PARSE_SFIXED64:
case OP_PARSE_SINT32:
case OP_PARSE_SINT64:
case OP_STARTSEQ:
case OP_ENDSEQ:
case OP_STARTSUBMSG:
case OP_ENDSUBMSG:
case OP_STARTSTR:
case OP_STRING:
case OP_ENDSTR:
case OP_PUSHTAGDELIM:
fprintf(f, " %d", instr >> 8);
break;
case OP_SETBIGGROUPNUM:
fprintf(f, " %d", *p++);
break;
case OP_CHECKDELIM:
case OP_CALL:
case OP_BRANCH:
fprintf(f, " =>0x%tx", p + getofs(instr) - begin);
break;
case OP_TAG1:
case OP_TAG2: {
fprintf(f, " tag:0x%x", instr >> 16);
if (getofs(instr)) {
fprintf(f, " =>0x%tx", p + getofs(instr) - begin);
}
break;
}
case OP_TAGN: {
uint64_t tag = *p++;
tag |= (uint64_t)*p++ << 32;
fprintf(f, " tag:0x%llx", (long long)tag);
fprintf(f, " n:%d", instr >> 16);
if (getofs(instr)) {
fprintf(f, " =>0x%tx", p + getofs(instr) - begin);
}
break;
}
}
fputs("\n", f);
}
}
#endif
static uint64_t get_encoded_tag(const upb_fielddef *f, int wire_type) {
uint32_t tag = (upb_fielddef_number(f) << 3) | wire_type;
uint64_t encoded_tag = upb_vencode32(tag);
/* No tag should be greater than 5 bytes. */
UPB_ASSERT(encoded_tag <= 0xffffffffff);
return encoded_tag;
}
static void putchecktag(compiler *c, const upb_fielddef *f,
int wire_type, int dest) {
uint64_t tag = get_encoded_tag(f, wire_type);
switch (upb_value_size(tag)) {
case 1:
putop(c, OP_TAG1, dest, tag);
break;
case 2:
putop(c, OP_TAG2, dest, tag);
break;
default:
putop(c, OP_TAGN, dest, tag);
break;
}
}
static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) {
upb_selector_t selector;
bool ok = upb_handlers_getselector(f, type, &selector);
UPB_ASSERT(ok);
return selector;
}
/* Takes an existing, primary dispatch table entry and repacks it with a
* different alternate wire type. Called when we are inserting a secondary
* dispatch table entry for an alternate wire type. */
static uint64_t repack(uint64_t dispatch, int new_wt2) {
uint64_t ofs;
uint8_t wt1;
uint8_t old_wt2;
upb_pbdecoder_unpackdispatch(dispatch, &ofs, &wt1, &old_wt2);
UPB_ASSERT(old_wt2 == NO_WIRE_TYPE); /* wt2 should not be set yet. */
return upb_pbdecoder_packdispatch(ofs, wt1, new_wt2);
}
/* Marks the current bytecode position as the dispatch target for this message,
* field, and wire type. */
static void dispatchtarget(compiler *c, upb_pbdecodermethod *method,
const upb_fielddef *f, int wire_type) {
/* Offset is relative to msg base. */
uint64_t ofs = pcofs(c) - method->code_base.ofs;
uint32_t fn = upb_fielddef_number(f);
upb_inttable *d = &method->dispatch;
upb_value v;
if (upb_inttable_remove(d, fn, &v)) {
/* TODO: prioritize based on packed setting in .proto file. */
uint64_t repacked = repack(upb_value_getuint64(v), wire_type);
upb_inttable_insert(d, fn, upb_value_uint64(repacked));
upb_inttable_insert(d, fn + UPB_MAX_FIELDNUMBER, upb_value_uint64(ofs));
} else {
uint64_t val = upb_pbdecoder_packdispatch(ofs, wire_type, NO_WIRE_TYPE);
upb_inttable_insert(d, fn, upb_value_uint64(val));
}
}
static void putpush(compiler *c, const upb_fielddef *f) {
if (upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE) {
putop(c, OP_PUSHLENDELIM);
} else {
uint32_t fn = upb_fielddef_number(f);
if (fn >= 1 << 24) {
putop(c, OP_PUSHTAGDELIM, 0);
putop(c, OP_SETBIGGROUPNUM, fn);
} else {
putop(c, OP_PUSHTAGDELIM, fn);
}
}
}
static upb_pbdecodermethod *find_submethod(const compiler *c,
const upb_pbdecodermethod *method,
const upb_fielddef *f) {
const upb_handlers *sub =
upb_handlers_getsubhandlers(method->dest_handlers_, f);
upb_value v;
return upb_inttable_lookupptr(&c->group->methods, sub, &v)
? upb_value_getptr(v)
: NULL;
}
static void putsel(compiler *c, opcode op, upb_selector_t sel,
const upb_handlers *h) {
if (upb_handlers_gethandler(h, sel, NULL)) {
putop(c, op, sel);
}
}
/* Puts an opcode to call a callback, but only if a callback actually exists for
* this field and handler type. */
static void maybeput(compiler *c, opcode op, const upb_handlers *h,
const upb_fielddef *f, upb_handlertype_t type) {
putsel(c, op, getsel(f, type), h);
}
static bool haslazyhandlers(const upb_handlers *h, const upb_fielddef *f) {
if (!upb_fielddef_lazy(f))
return false;
return upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_STARTSTR), NULL) ||
upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_STRING), NULL) ||
upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_ENDSTR), NULL);
}
/* bytecode compiler code generation ******************************************/
/* Symbolic names for our local labels. */
#define LABEL_LOOPSTART 1 /* Top of a repeated field loop. */
#define LABEL_LOOPBREAK 2 /* To jump out of a repeated loop */
#define LABEL_FIELD 3 /* Jump backward to find the most recent field. */
#define LABEL_ENDMSG 4 /* To reach the OP_ENDMSG instr for this msg. */
/* Generates bytecode to parse a single non-lazy message field. */
static void generate_msgfield(compiler *c, const upb_fielddef *f,
upb_pbdecodermethod *method) {
const upb_handlers *h = upb_pbdecodermethod_desthandlers(method);
const upb_pbdecodermethod *sub_m = find_submethod(c, method, f);
int wire_type;
if (!sub_m) {
/* Don't emit any code for this field at all; it will be parsed as an
* unknown field.
*
* TODO(haberman): we should change this to parse it as a string field
* instead. It will probably be faster, but more importantly, once we
* start vending unknown fields, a field shouldn't be treated as unknown
* just because it doesn't have subhandlers registered. */
return;
}
label(c, LABEL_FIELD);
wire_type =
(upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE)
? UPB_WIRE_TYPE_DELIMITED
: UPB_WIRE_TYPE_START_GROUP;
if (upb_fielddef_isseq(f)) {
putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
putchecktag(c, f, wire_type, LABEL_DISPATCH);
dispatchtarget(c, method, f, wire_type);
putop(c, OP_PUSHTAGDELIM, 0);
putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ));
label(c, LABEL_LOOPSTART);
putpush(c, f);
putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG));
putop(c, OP_CALL, sub_m);
putop(c, OP_POP);
maybeput(c, OP_ENDSUBMSG, h, f, UPB_HANDLER_ENDSUBMSG);
if (wire_type == UPB_WIRE_TYPE_DELIMITED) {
putop(c, OP_SETDELIM);
}
putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
putchecktag(c, f, wire_type, LABEL_LOOPBREAK);
putop(c, OP_BRANCH, -LABEL_LOOPSTART);
label(c, LABEL_LOOPBREAK);
putop(c, OP_POP);
maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ);
} else {
putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
putchecktag(c, f, wire_type, LABEL_DISPATCH);
dispatchtarget(c, method, f, wire_type);
putpush(c, f);
putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG));
putop(c, OP_CALL, sub_m);
putop(c, OP_POP);
maybeput(c, OP_ENDSUBMSG, h, f, UPB_HANDLER_ENDSUBMSG);
if (wire_type == UPB_WIRE_TYPE_DELIMITED) {
putop(c, OP_SETDELIM);
}
}
}
/* Generates bytecode to parse a single string or lazy submessage field. */
static void generate_delimfield(compiler *c, const upb_fielddef *f,
upb_pbdecodermethod *method) {
const upb_handlers *h = upb_pbdecodermethod_desthandlers(method);
label(c, LABEL_FIELD);
if (upb_fielddef_isseq(f)) {
putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH);
dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED);
putop(c, OP_PUSHTAGDELIM, 0);
putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ));
label(c, LABEL_LOOPSTART);
putop(c, OP_PUSHLENDELIM);
putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR));
/* Need to emit even if no handler to skip past the string. */
putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING));
maybeput(c, OP_ENDSTR, h, f, UPB_HANDLER_ENDSTR);
putop(c, OP_POP);
putop(c, OP_SETDELIM);
putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_LOOPBREAK);
putop(c, OP_BRANCH, -LABEL_LOOPSTART);
label(c, LABEL_LOOPBREAK);
putop(c, OP_POP);
maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ);
} else {
putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH);
dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED);
putop(c, OP_PUSHLENDELIM);
putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR));
putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING));
maybeput(c, OP_ENDSTR, h, f, UPB_HANDLER_ENDSTR);
putop(c, OP_POP);
putop(c, OP_SETDELIM);
}
}
/* Generates bytecode to parse a single primitive field. */
static void generate_primitivefield(compiler *c, const upb_fielddef *f,
upb_pbdecodermethod *method) {
const upb_handlers *h = upb_pbdecodermethod_desthandlers(method);
upb_descriptortype_t descriptor_type = upb_fielddef_descriptortype(f);
opcode parse_type;
upb_selector_t sel;
int wire_type;
label(c, LABEL_FIELD);
/* From a decoding perspective, ENUM is the same as INT32. */
if (descriptor_type == UPB_DESCRIPTOR_TYPE_ENUM)
descriptor_type = UPB_DESCRIPTOR_TYPE_INT32;
parse_type = (opcode)descriptor_type;
/* TODO(haberman): generate packed or non-packed first depending on "packed"
* setting in the fielddef. This will favor (in speed) whichever was
* specified. */
UPB_ASSERT((int)parse_type >= 0 && parse_type <= OP_MAX);
sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
wire_type = upb_pb_native_wire_types[upb_fielddef_descriptortype(f)];
if (upb_fielddef_isseq(f)) {
putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH);
dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED);
putop(c, OP_PUSHLENDELIM);
putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); /* Packed */
label(c, LABEL_LOOPSTART);
putop(c, parse_type, sel);
putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
putop(c, OP_BRANCH, -LABEL_LOOPSTART);
dispatchtarget(c, method, f, wire_type);
putop(c, OP_PUSHTAGDELIM, 0);
putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); /* Non-packed */
label(c, LABEL_LOOPSTART);
putop(c, parse_type, sel);
putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
putchecktag(c, f, wire_type, LABEL_LOOPBREAK);
putop(c, OP_BRANCH, -LABEL_LOOPSTART);
label(c, LABEL_LOOPBREAK);
putop(c, OP_POP); /* Packed and non-packed join. */
maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ);
putop(c, OP_SETDELIM); /* Could remove for non-packed by dup ENDSEQ. */
} else {
putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
putchecktag(c, f, wire_type, LABEL_DISPATCH);
dispatchtarget(c, method, f, wire_type);
putop(c, parse_type, sel);
}
}
/* Adds bytecode for parsing the given message to the given decoderplan,
* while adding all dispatch targets to this message's dispatch table. */
static void compile_method(compiler *c, upb_pbdecodermethod *method) {
const upb_handlers *h;
const upb_msgdef *md;
uint32_t* start_pc;
int i, n;
upb_value val;
UPB_ASSERT(method);
/* Clear all entries in the dispatch table. */
upb_inttable_uninit(&method->dispatch);
upb_inttable_init(&method->dispatch, UPB_CTYPE_UINT64);
h = upb_pbdecodermethod_desthandlers(method);
md = upb_handlers_msgdef(h);
method->code_base.ofs = pcofs(c);
putop(c, OP_SETDISPATCH, &method->dispatch);
putsel(c, OP_STARTMSG, UPB_STARTMSG_SELECTOR, h);
label(c, LABEL_FIELD);
start_pc = c->pc;
n = upb_msgdef_fieldcount(md);
for(i = 0; i < n; i++) {
const upb_fielddef *f = upb_msgdef_field(md, i);
upb_fieldtype_t type = upb_fielddef_type(f);
if (type == UPB_TYPE_MESSAGE && !(haslazyhandlers(h, f) && c->lazy)) {
generate_msgfield(c, f, method);
} else if (type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES ||
type == UPB_TYPE_MESSAGE) {
generate_delimfield(c, f, method);
} else {
generate_primitivefield(c, f, method);
}
}
/* If there were no fields, or if no handlers were defined, we need to
* generate a non-empty loop body so that we can at least dispatch for unknown
* fields and check for the end of the message. */
if (c->pc == start_pc) {
/* Check for end-of-message. */
putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
/* Unconditionally dispatch. */
putop(c, OP_DISPATCH, 0);
}
/* For now we just loop back to the last field of the message (or if none,
* the DISPATCH opcode for the message). */
putop(c, OP_BRANCH, -LABEL_FIELD);
/* Insert both a label and a dispatch table entry for this end-of-msg. */
label(c, LABEL_ENDMSG);
val = upb_value_uint64(pcofs(c) - method->code_base.ofs);
upb_inttable_insert(&method->dispatch, DISPATCH_ENDMSG, val);
putsel(c, OP_ENDMSG, UPB_ENDMSG_SELECTOR, h);
putop(c, OP_RET);
upb_inttable_compact(&method->dispatch);
}
/* Populate "methods" with new upb_pbdecodermethod objects reachable from "h".
* Returns the method for these handlers.
*
* Generates a new method for every destination handlers reachable from "h". */
static void find_methods(compiler *c, const upb_handlers *h) {
upb_value v;
int i, n;
const upb_msgdef *md;
upb_pbdecodermethod *method;
if (upb_inttable_lookupptr(&c->group->methods, h, &v))
return;
method = newmethod(h, c->group);
upb_inttable_insertptr(&c->group->methods, h, upb_value_ptr(method));
/* Find submethods. */
md = upb_handlers_msgdef(h);
n = upb_msgdef_fieldcount(md);
for (i = 0; i < n; i++) {
const upb_fielddef *f = upb_msgdef_field(md, i);
const upb_handlers *sub_h;
if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE &&
(sub_h = upb_handlers_getsubhandlers(h, f)) != NULL) {
/* We only generate a decoder method for submessages with handlers.
* Others will be parsed as unknown fields. */
find_methods(c, sub_h);
}
}
}
/* (Re-)compile bytecode for all messages in "msgs."
* Overwrites any existing bytecode in "c". */
static void compile_methods(compiler *c) {
upb_inttable_iter i;
/* Start over at the beginning of the bytecode. */
c->pc = c->group->bytecode;
upb_inttable_begin(&i, &c->group->methods);
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i));
compile_method(c, method);
}
}
static void set_bytecode_handlers(mgroup *g) {
upb_inttable_iter i;
upb_inttable_begin(&i, &g->methods);
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
upb_pbdecodermethod *m = upb_value_getptr(upb_inttable_iter_value(&i));
upb_byteshandler *h = &m->input_handler_;
m->code_base.ptr = g->bytecode + m->code_base.ofs;
upb_byteshandler_setstartstr(h, upb_pbdecoder_startbc, m->code_base.ptr);
upb_byteshandler_setstring(h, upb_pbdecoder_decode, g);
upb_byteshandler_setendstr(h, upb_pbdecoder_end, m);
}
}
/* TODO(haberman): allow this to be constructed for an arbitrary set of dest
* handlers and other mgroups (but verify we have a transitive closure). */
const mgroup *mgroup_new(const upb_handlers *dest, bool lazy) {
mgroup *g;
compiler *c;
g = newgroup();
c = newcompiler(g, lazy);
find_methods(c, dest);
/* We compile in two passes:
* 1. all messages are assigned relative offsets from the beginning of the
* bytecode (saved in method->code_base).
* 2. forwards OP_CALL instructions can be correctly linked since message
* offsets have been previously assigned.
*
* Could avoid the second pass by linking OP_CALL instructions somehow. */
compile_methods(c);
compile_methods(c);
g->bytecode_end = c->pc;
freecompiler(c);
#ifdef UPB_DUMP_BYTECODE
{
FILE *f = fopen("/tmp/upb-bytecode", "w");
UPB_ASSERT(f);
dumpbc(g->bytecode, g->bytecode_end, stderr);
dumpbc(g->bytecode, g->bytecode_end, f);
fclose(f);
f = fopen("/tmp/upb-bytecode.bin", "wb");
UPB_ASSERT(f);
fwrite(g->bytecode, 1, g->bytecode_end - g->bytecode, f);
fclose(f);
}
#endif
set_bytecode_handlers(g);
return g;
}
/* upb_pbcodecache ************************************************************/
upb_pbcodecache *upb_pbcodecache_new(upb_handlercache *dest) {
upb_pbcodecache *c = upb_gmalloc(sizeof(*c));
if (!c) return NULL;
c->dest = dest;
c->lazy = false;
c->arena = upb_arena_new();
if (!upb_inttable_init(&c->groups, UPB_CTYPE_CONSTPTR)) return NULL;
return c;
}
void upb_pbcodecache_free(upb_pbcodecache *c) {
upb_inttable_iter i;
upb_inttable_begin(&i, &c->groups);
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
upb_value val = upb_inttable_iter_value(&i);
freegroup((void*)upb_value_getconstptr(val));
}
upb_inttable_uninit(&c->groups);
upb_arena_free(c->arena);
upb_gfree(c);
}
void upb_pbdecodermethodopts_setlazy(upb_pbcodecache *c, bool lazy) {
UPB_ASSERT(upb_inttable_count(&c->groups) == 0);
c->lazy = lazy;
}
const upb_pbdecodermethod *upb_pbcodecache_get(upb_pbcodecache *c,
const upb_msgdef *md) {
upb_value v;
bool ok;
const upb_handlers *h;
const mgroup *g;
h = upb_handlercache_get(c->dest, md);
if (upb_inttable_lookupptr(&c->groups, md, &v)) {
g = upb_value_getconstptr(v);
} else {
g = mgroup_new(h, c->lazy);
ok = upb_inttable_insertptr(&c->groups, md, upb_value_constptr(g));
UPB_ASSUME(ok);
}
ok = upb_inttable_lookupptr(&g->methods, h, &v);
UPB_ASSUME(ok);
return upb_value_getptr(v);
}

File diff suppressed because it is too large Load Diff

@ -1,242 +0,0 @@
/*
** upb::pb::Decoder
**
** A high performance, streaming, resumable decoder for the binary protobuf
** format.
**
** This interface works the same regardless of what decoder backend is being
** used. A client of this class does not need to know whether decoding is using
** a JITted decoder (DynASM, LLVM, etc) or an interpreted decoder. By default,
** it will always use the fastest available decoder. However, you can call
** set_allow_jit(false) to disable any JIT decoder that might be available.
** This is primarily useful for testing purposes.
*/
#ifndef UPB_DECODER_H_
#define UPB_DECODER_H_
#include "upb/sink.h"
#ifdef __cplusplus
namespace upb {
namespace pb {
class CodeCache;
class DecoderPtr;
class DecoderMethodPtr;
class DecoderMethodOptions;
} /* namespace pb */
} /* namespace upb */
#endif
/* The maximum number of bytes we are required to buffer internally between
* calls to the decoder. The value is 14: a 5 byte unknown tag plus ten-byte
* varint, less one because we are buffering an incomplete value.
*
* Should only be used by unit tests. */
#define UPB_DECODER_MAX_RESIDUAL_BYTES 14
/* upb_pbdecodermethod ********************************************************/
struct upb_pbdecodermethod;
typedef struct upb_pbdecodermethod upb_pbdecodermethod;
#ifdef __cplusplus
extern "C" {
#endif
const upb_handlers *upb_pbdecodermethod_desthandlers(
const upb_pbdecodermethod *m);
const upb_byteshandler *upb_pbdecodermethod_inputhandler(
const upb_pbdecodermethod *m);
bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m);
#ifdef __cplusplus
} /* extern "C" */
/* Represents the code to parse a protobuf according to a destination
* Handlers. */
class upb::pb::DecoderMethodPtr {
public:
DecoderMethodPtr() : ptr_(nullptr) {}
DecoderMethodPtr(const upb_pbdecodermethod* ptr) : ptr_(ptr) {}
const upb_pbdecodermethod* ptr() { return ptr_; }
/* The destination handlers that are statically bound to this method.
* This method is only capable of outputting to a sink that uses these
* handlers. */
const Handlers *dest_handlers() const {
return upb_pbdecodermethod_desthandlers(ptr_);
}
/* The input handlers for this decoder method. */
const BytesHandler* input_handler() const {
return upb_pbdecodermethod_inputhandler(ptr_);
}
/* Whether this method is native. */
bool is_native() const {
return upb_pbdecodermethod_isnative(ptr_);
}
private:
const upb_pbdecodermethod* ptr_;
};
#endif
/* upb_pbdecoder **************************************************************/
/* Preallocation hint: decoder won't allocate more bytes than this when first
* constructed. This hint may be an overestimate for some build configurations.
* But if the decoder library is upgraded without recompiling the application,
* it may be an underestimate. */
#define UPB_PB_DECODER_SIZE 4416
struct upb_pbdecoder;
typedef struct upb_pbdecoder upb_pbdecoder;
#ifdef __cplusplus
extern "C" {
#endif
upb_pbdecoder *upb_pbdecoder_create(upb_arena *arena,
const upb_pbdecodermethod *method,
upb_sink output, upb_status *status);
const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d);
upb_bytessink upb_pbdecoder_input(upb_pbdecoder *d);
uint64_t upb_pbdecoder_bytesparsed(const upb_pbdecoder *d);
size_t upb_pbdecoder_maxnesting(const upb_pbdecoder *d);
bool upb_pbdecoder_setmaxnesting(upb_pbdecoder *d, size_t max);
void upb_pbdecoder_reset(upb_pbdecoder *d);
#ifdef __cplusplus
} /* extern "C" */
/* A Decoder receives binary protobuf data on its input sink and pushes the
* decoded data to its output sink. */
class upb::pb::DecoderPtr {
public:
DecoderPtr() : ptr_(nullptr) {}
DecoderPtr(upb_pbdecoder* ptr) : ptr_(ptr) {}
upb_pbdecoder* ptr() { return ptr_; }
/* Constructs a decoder instance for the given method, which must outlive this
* decoder. Any errors during parsing will be set on the given status, which
* must also outlive this decoder.
*
* The sink must match the given method. */
static DecoderPtr Create(Arena *arena, DecoderMethodPtr method,
upb::Sink output, Status *status) {
return DecoderPtr(upb_pbdecoder_create(arena->ptr(), method.ptr(),
output.sink(), status->ptr()));
}
/* Returns the DecoderMethod this decoder is parsing from. */
const DecoderMethodPtr method() const {
return DecoderMethodPtr(upb_pbdecoder_method(ptr_));
}
/* The sink on which this decoder receives input. */
BytesSink input() { return BytesSink(upb_pbdecoder_input(ptr())); }
/* Returns number of bytes successfully parsed.
*
* This can be useful for determining the stream position where an error
* occurred.
*
* This value may not be up-to-date when called from inside a parsing
* callback. */
uint64_t BytesParsed() { return upb_pbdecoder_bytesparsed(ptr()); }
/* Gets/sets the parsing nexting limit. If the total number of nested
* submessages and repeated fields hits this limit, parsing will fail. This
* is a resource limit that controls the amount of memory used by the parsing
* stack.
*
* Setting the limit will fail if the parser is currently suspended at a depth
* greater than this, or if memory allocation of the stack fails. */
size_t max_nesting() { return upb_pbdecoder_maxnesting(ptr()); }
bool set_max_nesting(size_t max) {
return upb_pbdecoder_setmaxnesting(ptr(), max);
}
void Reset() { upb_pbdecoder_reset(ptr()); }
static const size_t kSize = UPB_PB_DECODER_SIZE;
private:
upb_pbdecoder *ptr_;
};
#endif /* __cplusplus */
/* upb_pbcodecache ************************************************************/
/* Lazily builds and caches decoder methods that will push data to the given
* handlers. The destination handlercache must outlive this object. */
struct upb_pbcodecache;
typedef struct upb_pbcodecache upb_pbcodecache;
#ifdef __cplusplus
extern "C" {
#endif
upb_pbcodecache *upb_pbcodecache_new(upb_handlercache *dest);
void upb_pbcodecache_free(upb_pbcodecache *c);
bool upb_pbcodecache_allowjit(const upb_pbcodecache *c);
void upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow);
void upb_pbcodecache_setlazy(upb_pbcodecache *c, bool lazy);
const upb_pbdecodermethod *upb_pbcodecache_get(upb_pbcodecache *c,
const upb_msgdef *md);
#ifdef __cplusplus
} /* extern "C" */
/* A class for caching protobuf processing code, whether bytecode for the
* interpreted decoder or machine code for the JIT.
*
* This class is not thread-safe. */
class upb::pb::CodeCache {
public:
CodeCache(upb::HandlerCache *dest)
: ptr_(upb_pbcodecache_new(dest->ptr()), upb_pbcodecache_free) {}
CodeCache(CodeCache&&) = default;
CodeCache& operator=(CodeCache&&) = default;
upb_pbcodecache* ptr() { return ptr_.get(); }
const upb_pbcodecache* ptr() const { return ptr_.get(); }
/* Whether the cache is allowed to generate machine code. Defaults to true.
* There is no real reason to turn it off except for testing or if you are
* having a specific problem with the JIT.
*
* Note that allow_jit = true does not *guarantee* that the code will be JIT
* compiled. If this platform is not supported or the JIT was not compiled
* in, the code may still be interpreted. */
bool allow_jit() const { return upb_pbcodecache_allowjit(ptr()); }
/* This may only be called when the object is first constructed, and prior to
* any code generation. */
void set_allow_jit(bool allow) { upb_pbcodecache_setallowjit(ptr(), allow); }
/* Should the decoder push submessages to lazy handlers for fields that have
* them? The caller should set this iff the lazy handlers expect data that is
* in protobuf binary format and the caller wishes to lazy parse it. */
void set_lazy(bool lazy) { upb_pbcodecache_setlazy(ptr(), lazy); }
/* Returns a DecoderMethod that can push data to the given handlers.
* If a suitable method already exists, it will be returned from the cache. */
const DecoderMethodPtr Get(MessageDefPtr md) {
return DecoderMethodPtr(upb_pbcodecache_get(ptr(), md.ptr()));
}
private:
std::unique_ptr<upb_pbcodecache, decltype(&upb_pbcodecache_free)> ptr_;
};
#endif /* __cplusplus */
#endif /* UPB_DECODER_H_ */

@ -1,288 +0,0 @@
/*
** Internal-only definitions for the decoder.
*/
#ifndef UPB_DECODER_INT_H_
#define UPB_DECODER_INT_H_
#include "upb/def.h"
#include "upb/handlers.h"
#include "upb/pb/decoder.h"
#include "upb/sink.h"
#include "upb/table.int.h"
#include "upb/port_def.inc"
/* Opcode definitions. The canonical meaning of each opcode is its
* implementation in the interpreter (the JIT is written to match this).
*
* All instructions have the opcode in the low byte.
* Instruction format for most instructions is:
*
* +-------------------+--------+
* | arg (24) | op (8) |
* +-------------------+--------+
*
* Exceptions are indicated below. A few opcodes are multi-word. */
typedef enum {
/* Opcodes 1-8, 13, 15-18 parse their respective descriptor types.
* Arg for all of these is the upb selector for this field. */
#define T(type) OP_PARSE_ ## type = UPB_DESCRIPTOR_TYPE_ ## type
T(DOUBLE), T(FLOAT), T(INT64), T(UINT64), T(INT32), T(FIXED64), T(FIXED32),
T(BOOL), T(UINT32), T(SFIXED32), T(SFIXED64), T(SINT32), T(SINT64),
#undef T
OP_STARTMSG = 9, /* No arg. */
OP_ENDMSG = 10, /* No arg. */
OP_STARTSEQ = 11,
OP_ENDSEQ = 12,
OP_STARTSUBMSG = 14,
OP_ENDSUBMSG = 19,
OP_STARTSTR = 20,
OP_STRING = 21,
OP_ENDSTR = 22,
OP_PUSHTAGDELIM = 23, /* No arg. */
OP_PUSHLENDELIM = 24, /* No arg. */
OP_POP = 25, /* No arg. */
OP_SETDELIM = 26, /* No arg. */
OP_SETBIGGROUPNUM = 27, /* two words:
* | unused (24) | opc (8) |
* | groupnum (32) | */
OP_CHECKDELIM = 28,
OP_CALL = 29,
OP_RET = 30,
OP_BRANCH = 31,
/* Different opcodes depending on how many bytes expected. */
OP_TAG1 = 32, /* | match tag (16) | jump target (8) | opc (8) | */
OP_TAG2 = 33, /* | match tag (16) | jump target (8) | opc (8) | */
OP_TAGN = 34, /* three words: */
/* | unused (16) | jump target(8) | opc (8) | */
/* | match tag 1 (32) | */
/* | match tag 2 (32) | */
OP_SETDISPATCH = 35, /* N words: */
/* | unused (24) | opc | */
/* | upb_inttable* (32 or 64) | */
OP_DISPATCH = 36, /* No arg. */
OP_HALT = 37 /* No arg. */
} opcode;
#define OP_MAX OP_HALT
UPB_INLINE opcode getop(uint32_t instr) { return (opcode)(instr & 0xff); }
struct upb_pbcodecache {
upb_arena *arena;
upb_handlercache *dest;
bool allow_jit;
bool lazy;
/* Map of upb_msgdef -> mgroup. */
upb_inttable groups;
};
/* Method group; represents a set of decoder methods that had their code
* emitted together. Immutable once created. */
typedef struct {
/* Maps upb_msgdef/upb_handlers -> upb_pbdecodermethod. Owned by us.
*
* Ideally this would be on pbcodecache (if we were actually caching code).
* Right now we don't actually cache anything, which is wasteful. */
upb_inttable methods;
/* The bytecode for our methods, if any exists. Owned by us. */
uint32_t *bytecode;
uint32_t *bytecode_end;
} mgroup;
/* The maximum that any submessages can be nested. Matches proto2's limit.
* This specifies the size of the decoder's statically-sized array and therefore
* setting it high will cause the upb::pb::Decoder object to be larger.
*
* If necessary we can add a runtime-settable property to Decoder that allow
* this to be larger than the compile-time setting, but this would add
* complexity, particularly since we would have to decide how/if to give users
* the ability to set a custom memory allocation function. */
#define UPB_DECODER_MAX_NESTING 64
/* Internal-only struct used by the decoder. */
typedef struct {
/* Space optimization note: we store two pointers here that the JIT
* doesn't need at all; the upb_handlers* inside the sink and
* the dispatch table pointer. We can optimze so that the JIT uses
* smaller stack frames than the interpreter. The only thing we need
* to guarantee is that the fallback routines can find end_ofs. */
upb_sink sink;
/* The absolute stream offset of the end-of-frame delimiter.
* Non-delimited frames (groups and non-packed repeated fields) reuse the
* delimiter of their parent, even though the frame may not end there.
*
* NOTE: the JIT stores a slightly different value here for non-top frames.
* It stores the value relative to the end of the enclosed message. But the
* top frame is still stored the same way, which is important for ensuring
* that calls from the JIT into C work correctly. */
uint64_t end_ofs;
const uint32_t *base;
/* 0 indicates a length-delimited field.
* A positive number indicates a known group.
* A negative number indicates an unknown group. */
int32_t groupnum;
upb_inttable *dispatch; /* Not used by the JIT. */
} upb_pbdecoder_frame;
struct upb_pbdecodermethod {
/* While compiling, the base is relative in "ofs", after compiling it is
* absolute in "ptr". */
union {
uint32_t ofs; /* PC offset of method. */
void *ptr; /* Pointer to bytecode or machine code for this method. */
} code_base;
/* The decoder method group to which this method belongs. */
const mgroup *group;
/* Whether this method is native code or bytecode. */
bool is_native_;
/* The handler one calls to invoke this method. */
upb_byteshandler input_handler_;
/* The destination handlers this method is bound to. We own a ref. */
const upb_handlers *dest_handlers_;
/* Dispatch table -- used by both bytecode decoder and JIT when encountering a
* field number that wasn't the one we were expecting to see. See
* decoder.int.h for the layout of this table. */
upb_inttable dispatch;
};
struct upb_pbdecoder {
upb_arena *arena;
/* Our input sink. */
upb_bytessink input_;
/* The decoder method we are parsing with (owned). */
const upb_pbdecodermethod *method_;
size_t call_len;
const uint32_t *pc, *last;
/* Current input buffer and its stream offset. */
const char *buf, *ptr, *end, *checkpoint;
/* End of the delimited region, relative to ptr, NULL if not in this buf. */
const char *delim_end;
/* End of the delimited region, relative to ptr, end if not in this buf. */
const char *data_end;
/* Overall stream offset of "buf." */
uint64_t bufstart_ofs;
/* Buffer for residual bytes not parsed from the previous buffer. */
char residual[UPB_DECODER_MAX_RESIDUAL_BYTES];
char *residual_end;
/* Bytes of data that should be discarded from the input beore we start
* parsing again. We set this when we internally determine that we can
* safely skip the next N bytes, but this region extends past the current
* user buffer. */
size_t skip;
/* Stores the user buffer passed to our decode function. */
const char *buf_param;
size_t size_param;
const upb_bufhandle *handle;
/* Our internal stack. */
upb_pbdecoder_frame *stack, *top, *limit;
const uint32_t **callstack;
size_t stack_size;
upb_status *status;
};
/* Decoder entry points; used as handlers. */
void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint);
size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
size_t size, const upb_bufhandle *handle);
bool upb_pbdecoder_end(void *closure, const void *handler_data);
/* Decoder-internal functions that the JIT calls to handle fallback paths. */
int32_t upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf,
size_t size, const upb_bufhandle *handle);
size_t upb_pbdecoder_suspend(upb_pbdecoder *d);
int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, int32_t fieldnum,
uint8_t wire_type);
int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d, uint64_t expected);
int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d, uint64_t *u64);
int32_t upb_pbdecoder_decode_f32(upb_pbdecoder *d, uint32_t *u32);
int32_t upb_pbdecoder_decode_f64(upb_pbdecoder *d, uint64_t *u64);
void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg);
/* Error messages that are shared between the bytecode and JIT decoders. */
extern const char *kPbDecoderStackOverflow;
extern const char *kPbDecoderSubmessageTooLong;
/* Access to decoderplan members needed by the decoder. */
const char *upb_pbdecoder_getopname(unsigned int op);
/* A special label that means "do field dispatch for this message and branch to
* wherever that takes you." */
#define LABEL_DISPATCH 0
/* A special slot in the dispatch table that stores the epilogue (ENDMSG and/or
* RET) for branching to when we find an appropriate ENDGROUP tag. */
#define DISPATCH_ENDMSG 0
/* It's important to use this invalid wire type instead of 0 (which is a valid
* wire type). */
#define NO_WIRE_TYPE 0xff
/* The dispatch table layout is:
* [field number] -> [ 48-bit offset ][ 8-bit wt2 ][ 8-bit wt1 ]
*
* If wt1 matches, jump to the 48-bit offset. If wt2 matches, lookup
* (UPB_MAX_FIELDNUMBER + fieldnum) and jump there.
*
* We need two wire types because of packed/non-packed compatibility. A
* primitive repeated field can use either wire type and be valid. While we
* could key the table on fieldnum+wiretype, the table would be 8x sparser.
*
* Storing two wire types in the primary value allows us to quickly rule out
* the second wire type without needing to do a separate lookup (this case is
* less common than an unknown field). */
UPB_INLINE uint64_t upb_pbdecoder_packdispatch(uint64_t ofs, uint8_t wt1,
uint8_t wt2) {
return (ofs << 16) | (wt2 << 8) | wt1;
}
UPB_INLINE void upb_pbdecoder_unpackdispatch(uint64_t dispatch, uint64_t *ofs,
uint8_t *wt1, uint8_t *wt2) {
*wt1 = (uint8_t)dispatch;
*wt2 = (uint8_t)(dispatch >> 8);
*ofs = dispatch >> 16;
}
/* All of the functions in decoder.c that return int32_t return values according
* to the following scheme:
* 1. negative values indicate a return code from the following list.
* 2. positive values indicate that error or end of buffer was hit, and
* that the decode function should immediately return the given value
* (the decoder state has already been suspended and is ready to be
* resumed). */
#define DECODE_OK -1
#define DECODE_MISMATCH -2 /* Used only from checktag_slow(). */
#define DECODE_ENDGROUP -3 /* Used only from checkunknown(). */
#define CHECK_RETURN(x) { int32_t ret = x; if (ret >= 0) return ret; }
#include "upb/port_undef.inc"
#endif /* UPB_DECODER_INT_H_ */

@ -1,563 +0,0 @@
/*
** upb::Encoder
**
** Since we are implementing pure handlers (ie. without any out-of-band access
** to pre-computed lengths), we have to buffer all submessages before we can
** emit even their first byte.
**
** Not knowing the size of submessages also means we can't write a perfect
** zero-copy implementation, even with buffering. Lengths are stored as
** varints, which means that we don't know how many bytes to reserve for the
** length until we know what the length is.
**
** This leaves us with three main choices:
**
** 1. buffer all submessage data in a temporary buffer, then copy it exactly
** once into the output buffer.
**
** 2. attempt to buffer data directly into the output buffer, estimating how
** many bytes each length will take. When our guesses are wrong, use
** memmove() to grow or shrink the allotted space.
**
** 3. buffer directly into the output buffer, allocating a max length
** ahead-of-time for each submessage length. If we overallocated, we waste
** space, but no memcpy() or memmove() is required. This approach requires
** defining a maximum size for submessages and rejecting submessages that
** exceed that size.
**
** (2) and (3) have the potential to have better performance, but they are more
** complicated and subtle to implement:
**
** (3) requires making an arbitrary choice of the maximum message size; it
** wastes space when submessages are shorter than this and fails
** completely when they are longer. This makes it more finicky and
** requires configuration based on the input. It also makes it impossible
** to perfectly match the output of reference encoders that always use the
** optimal amount of space for each length.
**
** (2) requires guessing the the size upfront, and if multiple lengths are
** guessed wrong the minimum required number of memmove() operations may
** be complicated to compute correctly. Implemented properly, it may have
** a useful amortized or average cost, but more investigation is required
** to determine this and what the optimal algorithm is to achieve it.
**
** (1) makes you always pay for exactly one copy, but its implementation is
** the simplest and its performance is predictable.
**
** So for now, we implement (1) only. If we wish to optimize later, we should
** be able to do it without affecting users.
**
** The strategy is to buffer the segments of data that do *not* depend on
** unknown lengths in one buffer, and keep a separate buffer of segment pointers
** and lengths. When the top-level submessage ends, we can go beginning to end,
** alternating the writing of lengths with memcpy() of the rest of the data.
** At the top level though, no buffering is required.
*/
#include "upb/pb/encoder.h"
#include "upb/pb/varint.int.h"
#include "upb/port_def.inc"
/* The output buffer is divided into segments; a segment is a string of data
* that is "ready to go" -- it does not need any varint lengths inserted into
* the middle. The seams between segments are where varints will be inserted
* once they are known.
*
* We also use the concept of a "run", which is a range of encoded bytes that
* occur at a single submessage level. Every segment contains one or more runs.
*
* A segment can span messages. Consider:
*
* .--Submessage lengths---------.
* | | |
* | V V
* V | |--------------- | |-----------------
* Submessages: | |-----------------------------------------------
* Top-level msg: ------------------------------------------------------------
*
* Segments: ----- ------------------- -----------------
* Runs: *---- *--------------*--- *----------------
* (* marks the start)
*
* Note that the top-level menssage is not in any segment because it does not
* have any length preceding it.
*
* A segment is only interrupted when another length needs to be inserted. So
* observe how the second segment spans both the inner submessage and part of
* the next enclosing message. */
typedef struct {
uint32_t msglen; /* The length to varint-encode before this segment. */
uint32_t seglen; /* Length of the segment. */
} upb_pb_encoder_segment;
struct upb_pb_encoder {
upb_arena *arena;
/* Our input and output. */
upb_sink input_;
upb_bytessink output_;
/* The "subclosure" -- used as the inner closure as part of the bytessink
* protocol. */
void *subc;
/* The output buffer and limit, and our current write position. "buf"
* initially points to "initbuf", but is dynamically allocated if we need to
* grow beyond the initial size. */
char *buf, *ptr, *limit;
/* The beginning of the current run, or undefined if we are at the top
* level. */
char *runbegin;
/* The list of segments we are accumulating. */
upb_pb_encoder_segment *segbuf, *segptr, *seglimit;
/* The stack of enclosing submessages. Each entry in the stack points to the
* segment where this submessage's length is being accumulated. */
int *stack, *top, *stacklimit;
/* Depth of startmsg/endmsg calls. */
int depth;
};
/* low-level buffering ********************************************************/
/* Low-level functions for interacting with the output buffer. */
/* TODO(haberman): handle pushback */
static void putbuf(upb_pb_encoder *e, const char *buf, size_t len) {
size_t n = upb_bytessink_putbuf(e->output_, e->subc, buf, len, NULL);
UPB_ASSERT(n == len);
}
static upb_pb_encoder_segment *top(upb_pb_encoder *e) {
return &e->segbuf[*e->top];
}
/* Call to ensure that at least "bytes" bytes are available for writing at
* e->ptr. Returns false if the bytes could not be allocated. */
static bool reserve(upb_pb_encoder *e, size_t bytes) {
if ((size_t)(e->limit - e->ptr) < bytes) {
/* Grow buffer. */
char *new_buf;
size_t needed = bytes + (e->ptr - e->buf);
size_t old_size = e->limit - e->buf;
size_t new_size = old_size;
while (new_size < needed) {
new_size *= 2;
}
new_buf = upb_arena_realloc(e->arena, e->buf, old_size, new_size);
if (new_buf == NULL) {
return false;
}
e->ptr = new_buf + (e->ptr - e->buf);
e->runbegin = new_buf + (e->runbegin - e->buf);
e->limit = new_buf + new_size;
e->buf = new_buf;
}
return true;
}
/* Call when "bytes" bytes have been writte at e->ptr. The caller *must* have
* previously called reserve() with at least this many bytes. */
static void encoder_advance(upb_pb_encoder *e, size_t bytes) {
UPB_ASSERT((size_t)(e->limit - e->ptr) >= bytes);
e->ptr += bytes;
}
/* Call when all of the bytes for a handler have been written. Flushes the
* bytes if possible and necessary, returning false if this failed. */
static bool commit(upb_pb_encoder *e) {
if (!e->top) {
/* We aren't inside a delimited region. Flush our accumulated bytes to
* the output.
*
* TODO(haberman): in the future we may want to delay flushing for
* efficiency reasons. */
putbuf(e, e->buf, e->ptr - e->buf);
e->ptr = e->buf;
}
return true;
}
/* Writes the given bytes to the buffer, handling reserve/advance. */
static bool encode_bytesval(upb_pb_encoder *e, const void *data, size_t len) {
if (!reserve(e, len)) {
return false;
}
memcpy(e->ptr, data, len);
encoder_advance(e, len);
return true;
}
/* Finish the current run by adding the run totals to the segment and message
* length. */
static void accumulate(upb_pb_encoder *e) {
size_t run_len;
UPB_ASSERT(e->ptr >= e->runbegin);
run_len = e->ptr - e->runbegin;
e->segptr->seglen += run_len;
top(e)->msglen += run_len;
e->runbegin = e->ptr;
}
/* Call to indicate the start of delimited region for which the full length is
* not yet known. All data will be buffered until the length is known.
* Delimited regions may be nested; their lengths will all be tracked properly. */
static bool start_delim(upb_pb_encoder *e) {
if (e->top) {
/* We are already buffering, advance to the next segment and push it on the
* stack. */
accumulate(e);
if (++e->top == e->stacklimit) {
/* TODO(haberman): grow stack? */
return false;
}
if (++e->segptr == e->seglimit) {
/* Grow segment buffer. */
size_t old_size =
(e->seglimit - e->segbuf) * sizeof(upb_pb_encoder_segment);
size_t new_size = old_size * 2;
upb_pb_encoder_segment *new_buf =
upb_arena_realloc(e->arena, e->segbuf, old_size, new_size);
if (new_buf == NULL) {
return false;
}
e->segptr = new_buf + (e->segptr - e->segbuf);
e->seglimit = new_buf + (new_size / sizeof(upb_pb_encoder_segment));
e->segbuf = new_buf;
}
} else {
/* We were previously at the top level, start buffering. */
e->segptr = e->segbuf;
e->top = e->stack;
e->runbegin = e->ptr;
}
*e->top = (int)(e->segptr - e->segbuf);
e->segptr->seglen = 0;
e->segptr->msglen = 0;
return true;
}
/* Call to indicate the end of a delimited region. We now know the length of
* the delimited region. If we are not nested inside any other delimited
* regions, we can now emit all of the buffered data we accumulated. */
static bool end_delim(upb_pb_encoder *e) {
size_t msglen;
accumulate(e);
msglen = top(e)->msglen;
if (e->top == e->stack) {
/* All lengths are now available, emit all buffered data. */
char buf[UPB_PB_VARINT_MAX_LEN];
upb_pb_encoder_segment *s;
const char *ptr = e->buf;
for (s = e->segbuf; s <= e->segptr; s++) {
size_t lenbytes = upb_vencode64(s->msglen, buf);
putbuf(e, buf, lenbytes);
putbuf(e, ptr, s->seglen);
ptr += s->seglen;
}
e->ptr = e->buf;
e->top = NULL;
} else {
/* Need to keep buffering; propagate length info into enclosing
* submessages. */
--e->top;
top(e)->msglen += msglen + upb_varint_size(msglen);
}
return true;
}
/* tag_t **********************************************************************/
/* A precomputed (pre-encoded) tag and length. */
typedef struct {
uint8_t bytes;
char tag[7];
} tag_t;
/* Allocates a new tag for this field, and sets it in these handlerattr. */
static void new_tag(upb_handlers *h, const upb_fielddef *f, upb_wiretype_t wt,
upb_handlerattr *attr) {
uint32_t n = upb_fielddef_number(f);
tag_t *tag = upb_gmalloc(sizeof(tag_t));
tag->bytes = upb_vencode64((n << 3) | wt, tag->tag);
attr->handler_data = tag;
upb_handlers_addcleanup(h, tag, upb_gfree);
}
static bool encode_tagval(upb_pb_encoder *e, const tag_t *tag) {
return encode_bytesval(e, tag->tag, tag->bytes);
}
/* encoding of wire types *****************************************************/
static bool doencode_fixed64(upb_pb_encoder *e, uint64_t val) {
/* TODO(haberman): byte-swap for big endian. */
return encode_bytesval(e, &val, sizeof(uint64_t));
}
static bool doencode_fixed32(upb_pb_encoder *e, uint32_t val) {
/* TODO(haberman): byte-swap for big endian. */
return encode_bytesval(e, &val, sizeof(uint32_t));
}
static bool doencode_varint(upb_pb_encoder *e, uint64_t val) {
if (!reserve(e, UPB_PB_VARINT_MAX_LEN)) {
return false;
}
encoder_advance(e, upb_vencode64(val, e->ptr));
return true;
}
static uint64_t dbl2uint64(double d) {
uint64_t ret;
memcpy(&ret, &d, sizeof(uint64_t));
return ret;
}
static uint32_t flt2uint32(float d) {
uint32_t ret;
memcpy(&ret, &d, sizeof(uint32_t));
return ret;
}
/* encoding of proto types ****************************************************/
static bool startmsg(void *c, const void *hd) {
upb_pb_encoder *e = c;
UPB_UNUSED(hd);
if (e->depth++ == 0) {
upb_bytessink_start(e->output_, 0, &e->subc);
}
return true;
}
static bool endmsg(void *c, const void *hd, upb_status *status) {
upb_pb_encoder *e = c;
UPB_UNUSED(hd);
UPB_UNUSED(status);
if (--e->depth == 0) {
upb_bytessink_end(e->output_);
}
return true;
}
static void *encode_startdelimfield(void *c, const void *hd) {
bool ok = encode_tagval(c, hd) && commit(c) && start_delim(c);
return ok ? c : UPB_BREAK;
}
static bool encode_unknown(void *c, const void *hd, const char *buf,
size_t len) {
UPB_UNUSED(hd);
return encode_bytesval(c, buf, len) && commit(c);
}
static bool encode_enddelimfield(void *c, const void *hd) {
UPB_UNUSED(hd);
return end_delim(c);
}
static void *encode_startgroup(void *c, const void *hd) {
return (encode_tagval(c, hd) && commit(c)) ? c : UPB_BREAK;
}
static bool encode_endgroup(void *c, const void *hd) {
return encode_tagval(c, hd) && commit(c);
}
static void *encode_startstr(void *c, const void *hd, size_t size_hint) {
UPB_UNUSED(size_hint);
return encode_startdelimfield(c, hd);
}
static size_t encode_strbuf(void *c, const void *hd, const char *buf,
size_t len, const upb_bufhandle *h) {
UPB_UNUSED(hd);
UPB_UNUSED(h);
return encode_bytesval(c, buf, len) ? len : 0;
}
#define T(type, ctype, convert, encode) \
static bool encode_scalar_##type(void *e, const void *hd, ctype val) { \
return encode_tagval(e, hd) && encode(e, (convert)(val)) && commit(e); \
} \
static bool encode_packed_##type(void *e, const void *hd, ctype val) { \
UPB_UNUSED(hd); \
return encode(e, (convert)(val)); \
}
T(double, double, dbl2uint64, doencode_fixed64)
T(float, float, flt2uint32, doencode_fixed32)
T(int64, int64_t, uint64_t, doencode_varint)
T(int32, int32_t, int64_t, doencode_varint)
T(fixed64, uint64_t, uint64_t, doencode_fixed64)
T(fixed32, uint32_t, uint32_t, doencode_fixed32)
T(bool, bool, bool, doencode_varint)
T(uint32, uint32_t, uint32_t, doencode_varint)
T(uint64, uint64_t, uint64_t, doencode_varint)
T(enum, int32_t, uint32_t, doencode_varint)
T(sfixed32, int32_t, uint32_t, doencode_fixed32)
T(sfixed64, int64_t, uint64_t, doencode_fixed64)
T(sint32, int32_t, upb_zzenc_32, doencode_varint)
T(sint64, int64_t, upb_zzenc_64, doencode_varint)
#undef T
/* code to build the handlers *************************************************/
#include <stdio.h>
static void newhandlers_callback(const void *closure, upb_handlers *h) {
const upb_msgdef *m;
int i, n;
UPB_UNUSED(closure);
upb_handlers_setstartmsg(h, startmsg, NULL);
upb_handlers_setendmsg(h, endmsg, NULL);
upb_handlers_setunknown(h, encode_unknown, NULL);
m = upb_handlers_msgdef(h);
n = upb_msgdef_fieldcount(m);
for(i = 0; i < n; i++) {
const upb_fielddef *f = upb_msgdef_field(m, i);
bool packed = upb_fielddef_isseq(f) && upb_fielddef_isprimitive(f) &&
upb_fielddef_packed(f);
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
upb_wiretype_t wt =
packed ? UPB_WIRE_TYPE_DELIMITED
: upb_pb_native_wire_types[upb_fielddef_descriptortype(f)];
/* Pre-encode the tag for this field. */
new_tag(h, f, wt, &attr);
if (packed) {
upb_handlers_setstartseq(h, f, encode_startdelimfield, &attr);
upb_handlers_setendseq(h, f, encode_enddelimfield, &attr);
}
#define T(upper, lower, upbtype) \
case UPB_DESCRIPTOR_TYPE_##upper: \
if (packed) { \
upb_handlers_set##upbtype(h, f, encode_packed_##lower, &attr); \
} else { \
upb_handlers_set##upbtype(h, f, encode_scalar_##lower, &attr); \
} \
break;
switch (upb_fielddef_descriptortype(f)) {
T(DOUBLE, double, double);
T(FLOAT, float, float);
T(INT64, int64, int64);
T(INT32, int32, int32);
T(FIXED64, fixed64, uint64);
T(FIXED32, fixed32, uint32);
T(BOOL, bool, bool);
T(UINT32, uint32, uint32);
T(UINT64, uint64, uint64);
T(ENUM, enum, int32);
T(SFIXED32, sfixed32, int32);
T(SFIXED64, sfixed64, int64);
T(SINT32, sint32, int32);
T(SINT64, sint64, int64);
case UPB_DESCRIPTOR_TYPE_STRING:
case UPB_DESCRIPTOR_TYPE_BYTES:
upb_handlers_setstartstr(h, f, encode_startstr, &attr);
upb_handlers_setendstr(h, f, encode_enddelimfield, &attr);
upb_handlers_setstring(h, f, encode_strbuf, &attr);
break;
case UPB_DESCRIPTOR_TYPE_MESSAGE:
upb_handlers_setstartsubmsg(h, f, encode_startdelimfield, &attr);
upb_handlers_setendsubmsg(h, f, encode_enddelimfield, &attr);
break;
case UPB_DESCRIPTOR_TYPE_GROUP: {
/* Endgroup takes a different tag (wire_type = END_GROUP). */
upb_handlerattr attr2 = UPB_HANDLERATTR_INIT;
new_tag(h, f, UPB_WIRE_TYPE_END_GROUP, &attr2);
upb_handlers_setstartsubmsg(h, f, encode_startgroup, &attr);
upb_handlers_setendsubmsg(h, f, encode_endgroup, &attr2);
break;
}
}
#undef T
}
}
void upb_pb_encoder_reset(upb_pb_encoder *e) {
e->segptr = NULL;
e->top = NULL;
e->depth = 0;
}
/* public API *****************************************************************/
upb_handlercache *upb_pb_encoder_newcache(void) {
return upb_handlercache_new(newhandlers_callback, NULL);
}
upb_pb_encoder *upb_pb_encoder_create(upb_arena *arena, const upb_handlers *h,
upb_bytessink output) {
const size_t initial_bufsize = 256;
const size_t initial_segbufsize = 16;
/* TODO(haberman): make this configurable. */
const size_t stack_size = 64;
upb_pb_encoder *e = upb_arena_malloc(arena, sizeof(upb_pb_encoder));
if (!e) return NULL;
e->buf = upb_arena_malloc(arena, initial_bufsize);
e->segbuf = upb_arena_malloc(arena, initial_segbufsize * sizeof(*e->segbuf));
e->stack = upb_arena_malloc(arena, stack_size * sizeof(*e->stack));
if (!e->buf || !e->segbuf || !e->stack) {
return NULL;
}
e->limit = e->buf + initial_bufsize;
e->seglimit = e->segbuf + initial_segbufsize;
e->stacklimit = e->stack + stack_size;
upb_pb_encoder_reset(e);
upb_sink_reset(&e->input_, h, e);
e->arena = arena;
e->output_ = output;
e->subc = output.closure;
e->ptr = e->buf;
return e;
}
upb_sink upb_pb_encoder_input(upb_pb_encoder *e) { return e->input_; }

@ -1,83 +0,0 @@
/*
** upb::pb::Encoder (upb_pb_encoder)
**
** Implements a set of upb_handlers that write protobuf data to the binary wire
** format.
**
** This encoder implementation does not have any access to any out-of-band or
** precomputed lengths for submessages, so it must buffer submessages internally
** before it can emit the first byte.
*/
#ifndef UPB_ENCODER_H_
#define UPB_ENCODER_H_
#include "upb/sink.h"
#ifdef __cplusplus
namespace upb {
namespace pb {
class EncoderPtr;
} /* namespace pb */
} /* namespace upb */
#endif
#define UPB_PBENCODER_MAX_NESTING 100
/* upb_pb_encoder *************************************************************/
/* Preallocation hint: decoder won't allocate more bytes than this when first
* constructed. This hint may be an overestimate for some build configurations.
* But if the decoder library is upgraded without recompiling the application,
* it may be an underestimate. */
#define UPB_PB_ENCODER_SIZE 784
struct upb_pb_encoder;
typedef struct upb_pb_encoder upb_pb_encoder;
#ifdef __cplusplus
extern "C" {
#endif
upb_sink upb_pb_encoder_input(upb_pb_encoder *p);
upb_pb_encoder* upb_pb_encoder_create(upb_arena* a, const upb_handlers* h,
upb_bytessink output);
/* Lazily builds and caches handlers that will push encoded data to a bytessink.
* Any msgdef objects used with this object must outlive it. */
upb_handlercache *upb_pb_encoder_newcache(void);
#ifdef __cplusplus
} /* extern "C" { */
class upb::pb::EncoderPtr {
public:
EncoderPtr(upb_pb_encoder* ptr) : ptr_(ptr) {}
upb_pb_encoder* ptr() { return ptr_; }
/* Creates a new encoder in the given environment. The Handlers must have
* come from NewHandlers() below. */
static EncoderPtr Create(Arena* arena, const Handlers* handlers,
BytesSink output) {
return EncoderPtr(
upb_pb_encoder_create(arena->ptr(), handlers, output.sink()));
}
/* The input to the encoder. */
upb::Sink input() { return upb_pb_encoder_input(ptr()); }
/* Creates a new set of handlers for this MessageDef. */
static HandlerCache NewCache() {
return HandlerCache(upb_pb_encoder_newcache());
}
static const size_t kSize = UPB_PB_ENCODER_SIZE;
private:
upb_pb_encoder* ptr_;
};
#endif /* __cplusplus */
#endif /* UPB_ENCODER_H_ */

@ -1,36 +0,0 @@
#!/usr/bin/ruby
puts "set width 0
set height 0
set verbose off\n\n"
IO.popen("nm -S /tmp/upb-jit-code.so").each_line { |line|
# Input lines look like this:
# 000000000000575a T X.0x10.OP_CHECKDELIM
#
# For each one we want to emit a command that looks like:
# b X.0x10.OP_CHECKDELIM
# commands
# silent
# printf "buf_ofs=%d data_rem=%d delim_rem=%d X.0x10.OP_CHECKDELIM\n", $rbx - (long)((upb_pbdecoder*)($r15))->buf, $r12 - $rbx, $rbp - $rbx
# continue
# end
parts = line.split
next if parts[1] != "T"
sym = parts[2]
next if sym !~ /X\./;
if sym =~ /OP_/ then
printcmd = "printf \"buf_ofs=%d data_rem=%d delim_rem=%d #{sym}\\n\", $rbx - (long)((upb_pbdecoder*)($r15))->buf, $r12 - $rbx, $rbp - $rbx"
elsif sym =~ /enterjit/ then
printcmd = "printf \"#{sym} bytes=%d\\n\", $rcx"
else
printcmd = "printf \"#{sym}\\n\""
end
puts "b #{sym}
commands
silent
#{printcmd}
continue
end\n\n"
}

@ -1,339 +0,0 @@
/*
* upb::pb::TextPrinter
*
* OPT: This is not optimized at all. It uses printf() which parses the format
* string every time, and it allocates memory for every put.
*/
#include "upb/pb/textprinter.h"
#include <ctype.h>
#include <float.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "upb/sink.h"
#include "upb/port_def.inc"
struct upb_textprinter {
upb_sink input_;
upb_bytessink output_;
int indent_depth_;
bool single_line_;
void *subc;
};
#define CHECK(x) if ((x) < 0) goto err;
static const char *shortname(const char *longname) {
const char *last = strrchr(longname, '.');
return last ? last + 1 : longname;
}
static int indent(upb_textprinter *p) {
int i;
if (!p->single_line_)
for (i = 0; i < p->indent_depth_; i++)
upb_bytessink_putbuf(p->output_, p->subc, " ", 2, NULL);
return 0;
}
static int endfield(upb_textprinter *p) {
const char ch = (p->single_line_ ? ' ' : '\n');
upb_bytessink_putbuf(p->output_, p->subc, &ch, 1, NULL);
return 0;
}
static int putescaped(upb_textprinter *p, const char *buf, size_t len,
bool preserve_utf8) {
/* Based on CEscapeInternal() from Google's protobuf release. */
char dstbuf[4096], *dst = dstbuf, *dstend = dstbuf + sizeof(dstbuf);
const char *end = buf + len;
/* I think hex is prettier and more useful, but proto2 uses octal; should
* investigate whether it can parse hex also. */
const bool use_hex = false;
bool last_hex_escape = false; /* true if last output char was \xNN */
for (; buf < end; buf++) {
bool is_hex_escape;
if (dstend - dst < 4) {
upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL);
dst = dstbuf;
}
is_hex_escape = false;
switch (*buf) {
case '\n': *(dst++) = '\\'; *(dst++) = 'n'; break;
case '\r': *(dst++) = '\\'; *(dst++) = 'r'; break;
case '\t': *(dst++) = '\\'; *(dst++) = 't'; break;
case '\"': *(dst++) = '\\'; *(dst++) = '\"'; break;
case '\'': *(dst++) = '\\'; *(dst++) = '\''; break;
case '\\': *(dst++) = '\\'; *(dst++) = '\\'; break;
default:
/* Note that if we emit \xNN and the buf character after that is a hex
* digit then that digit must be escaped too to prevent it being
* interpreted as part of the character code by C. */
if ((!preserve_utf8 || (uint8_t)*buf < 0x80) &&
(!isprint(*buf) || (last_hex_escape && isxdigit(*buf)))) {
sprintf(dst, (use_hex ? "\\x%02x" : "\\%03o"), (uint8_t)*buf);
is_hex_escape = use_hex;
dst += 4;
} else {
*(dst++) = *buf; break;
}
}
last_hex_escape = is_hex_escape;
}
/* Flush remaining data. */
upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL);
return 0;
}
bool putf(upb_textprinter *p, const char *fmt, ...) {
va_list args;
va_list args_copy;
char *str;
int written;
int len;
bool ok;
va_start(args, fmt);
/* Run once to get the length of the string. */
va_copy(args_copy, args);
len = vsnprintf(NULL, 0, fmt, args_copy);
va_end(args_copy);
/* + 1 for NULL terminator (vsprintf() requires it even if we don't). */
str = upb_gmalloc(len + 1);
if (!str) return false;
written = vsprintf(str, fmt, args);
va_end(args);
UPB_ASSERT(written == len);
ok = upb_bytessink_putbuf(p->output_, p->subc, str, len, NULL);
upb_gfree(str);
return ok;
}
/* handlers *******************************************************************/
static bool textprinter_startmsg(void *c, const void *hd) {
upb_textprinter *p = c;
UPB_UNUSED(hd);
if (p->indent_depth_ == 0) {
upb_bytessink_start(p->output_, 0, &p->subc);
}
return true;
}
static bool textprinter_endmsg(void *c, const void *hd, upb_status *s) {
upb_textprinter *p = c;
UPB_UNUSED(hd);
UPB_UNUSED(s);
if (p->indent_depth_ == 0) {
upb_bytessink_end(p->output_);
}
return true;
}
#define TYPE(name, ctype, fmt) \
static bool textprinter_put ## name(void *closure, const void *handler_data, \
ctype val) { \
upb_textprinter *p = closure; \
const upb_fielddef *f = handler_data; \
CHECK(indent(p)); \
putf(p, "%s: " fmt, upb_fielddef_name(f), val); \
CHECK(endfield(p)); \
return true; \
err: \
return false; \
}
static bool textprinter_putbool(void *closure, const void *handler_data,
bool val) {
upb_textprinter *p = closure;
const upb_fielddef *f = handler_data;
CHECK(indent(p));
putf(p, "%s: %s", upb_fielddef_name(f), val ? "true" : "false");
CHECK(endfield(p));
return true;
err:
return false;
}
#define STRINGIFY_HELPER(x) #x
#define STRINGIFY_MACROVAL(x) STRINGIFY_HELPER(x)
TYPE(int32, int32_t, "%" PRId32)
TYPE(int64, int64_t, "%" PRId64)
TYPE(uint32, uint32_t, "%" PRIu32)
TYPE(uint64, uint64_t, "%" PRIu64)
TYPE(float, float, "%." STRINGIFY_MACROVAL(FLT_DIG) "g")
TYPE(double, double, "%." STRINGIFY_MACROVAL(DBL_DIG) "g")
#undef TYPE
/* Output a symbolic value from the enum if found, else just print as int32. */
static bool textprinter_putenum(void *closure, const void *handler_data,
int32_t val) {
upb_textprinter *p = closure;
const upb_fielddef *f = handler_data;
const upb_enumdef *enum_def = upb_fielddef_enumsubdef(f);
const char *label = upb_enumdef_iton(enum_def, val);
if (label) {
indent(p);
putf(p, "%s: %s", upb_fielddef_name(f), label);
endfield(p);
} else {
if (!textprinter_putint32(closure, handler_data, val))
return false;
}
return true;
}
static void *textprinter_startstr(void *closure, const void *handler_data,
size_t size_hint) {
upb_textprinter *p = closure;
const upb_fielddef *f = handler_data;
UPB_UNUSED(size_hint);
indent(p);
putf(p, "%s: \"", upb_fielddef_name(f));
return p;
}
static bool textprinter_endstr(void *closure, const void *handler_data) {
upb_textprinter *p = closure;
UPB_UNUSED(handler_data);
putf(p, "\"");
endfield(p);
return true;
}
static size_t textprinter_putstr(void *closure, const void *hd, const char *buf,
size_t len, const upb_bufhandle *handle) {
upb_textprinter *p = closure;
const upb_fielddef *f = hd;
UPB_UNUSED(handle);
CHECK(putescaped(p, buf, len, upb_fielddef_type(f) == UPB_TYPE_STRING));
return len;
err:
return 0;
}
static void *textprinter_startsubmsg(void *closure, const void *handler_data) {
upb_textprinter *p = closure;
const char *name = handler_data;
CHECK(indent(p));
putf(p, "%s {%c", name, p->single_line_ ? ' ' : '\n');
p->indent_depth_++;
return p;
err:
return UPB_BREAK;
}
static bool textprinter_endsubmsg(void *closure, const void *handler_data) {
upb_textprinter *p = closure;
UPB_UNUSED(handler_data);
p->indent_depth_--;
CHECK(indent(p));
upb_bytessink_putbuf(p->output_, p->subc, "}", 1, NULL);
CHECK(endfield(p));
return true;
err:
return false;
}
static void onmreg(const void *c, upb_handlers *h) {
const upb_msgdef *m = upb_handlers_msgdef(h);
int i, n;
UPB_UNUSED(c);
upb_handlers_setstartmsg(h, textprinter_startmsg, NULL);
upb_handlers_setendmsg(h, textprinter_endmsg, NULL);
n = upb_msgdef_fieldcount(m);
for(i = 0; i < n; i++) {
const upb_fielddef *f = upb_msgdef_field(m, i);
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
attr.handler_data = f;
switch (upb_fielddef_type(f)) {
case UPB_TYPE_INT32:
upb_handlers_setint32(h, f, textprinter_putint32, &attr);
break;
case UPB_TYPE_INT64:
upb_handlers_setint64(h, f, textprinter_putint64, &attr);
break;
case UPB_TYPE_UINT32:
upb_handlers_setuint32(h, f, textprinter_putuint32, &attr);
break;
case UPB_TYPE_UINT64:
upb_handlers_setuint64(h, f, textprinter_putuint64, &attr);
break;
case UPB_TYPE_FLOAT:
upb_handlers_setfloat(h, f, textprinter_putfloat, &attr);
break;
case UPB_TYPE_DOUBLE:
upb_handlers_setdouble(h, f, textprinter_putdouble, &attr);
break;
case UPB_TYPE_BOOL:
upb_handlers_setbool(h, f, textprinter_putbool, &attr);
break;
case UPB_TYPE_STRING:
case UPB_TYPE_BYTES:
upb_handlers_setstartstr(h, f, textprinter_startstr, &attr);
upb_handlers_setstring(h, f, textprinter_putstr, &attr);
upb_handlers_setendstr(h, f, textprinter_endstr, &attr);
break;
case UPB_TYPE_MESSAGE: {
const char *name =
upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_GROUP
? shortname(upb_msgdef_fullname(upb_fielddef_msgsubdef(f)))
: upb_fielddef_name(f);
attr.handler_data = name;
upb_handlers_setstartsubmsg(h, f, textprinter_startsubmsg, &attr);
upb_handlers_setendsubmsg(h, f, textprinter_endsubmsg, &attr);
break;
}
case UPB_TYPE_ENUM:
upb_handlers_setint32(h, f, textprinter_putenum, &attr);
break;
}
}
}
static void textprinter_reset(upb_textprinter *p, bool single_line) {
p->single_line_ = single_line;
p->indent_depth_ = 0;
}
/* Public API *****************************************************************/
upb_textprinter *upb_textprinter_create(upb_arena *arena, const upb_handlers *h,
upb_bytessink output) {
upb_textprinter *p = upb_arena_malloc(arena, sizeof(upb_textprinter));
if (!p) return NULL;
p->output_ = output;
upb_sink_reset(&p->input_, h, p);
textprinter_reset(p, false);
return p;
}
upb_handlercache *upb_textprinter_newcache(void) {
return upb_handlercache_new(&onmreg, NULL);
}
upb_sink upb_textprinter_input(upb_textprinter *p) { return p->input_; }
void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line) {
p->single_line_ = single_line;
}

@ -1,69 +0,0 @@
/*
** upb::pb::TextPrinter (upb_textprinter)
**
** Handlers for writing to protobuf text format.
*/
#ifndef UPB_TEXT_H_
#define UPB_TEXT_H_
#include "upb/sink.h"
#ifdef __cplusplus
namespace upb {
namespace pb {
class TextPrinterPtr;
} /* namespace pb */
} /* namespace upb */
#endif
/* upb_textprinter ************************************************************/
struct upb_textprinter;
typedef struct upb_textprinter upb_textprinter;
#ifdef __cplusplus
extern "C" {
#endif
/* C API. */
upb_textprinter *upb_textprinter_create(upb_arena *arena, const upb_handlers *h,
upb_bytessink output);
void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line);
upb_sink upb_textprinter_input(upb_textprinter *p);
upb_handlercache *upb_textprinter_newcache(void);
#ifdef __cplusplus
} /* extern "C" */
class upb::pb::TextPrinterPtr {
public:
TextPrinterPtr(upb_textprinter* ptr) : ptr_(ptr) {}
/* The given handlers must have come from NewHandlers(). It must outlive the
* TextPrinter. */
static TextPrinterPtr Create(Arena *arena, upb::HandlersPtr *handlers,
BytesSink output) {
return TextPrinterPtr(
upb_textprinter_create(arena->ptr(), handlers->ptr(), output.sink()));
}
void SetSingleLineMode(bool single_line) {
upb_textprinter_setsingleline(ptr_, single_line);
}
Sink input() { return upb_textprinter_input(ptr_); }
/* If handler caching becomes a requirement we can add a code cache as in
* decoder.h */
static HandlerCache NewCache() {
return HandlerCache(upb_textprinter_newcache());
}
private:
upb_textprinter* ptr_;
};
#endif
#endif /* UPB_TEXT_H_ */

@ -1,74 +0,0 @@
#include "upb/pb/varint.int.h"
/* Index is descriptor type. */
const uint8_t upb_pb_native_wire_types[] = {
UPB_WIRE_TYPE_END_GROUP, /* ENDGROUP */
UPB_WIRE_TYPE_64BIT, /* DOUBLE */
UPB_WIRE_TYPE_32BIT, /* FLOAT */
UPB_WIRE_TYPE_VARINT, /* INT64 */
UPB_WIRE_TYPE_VARINT, /* UINT64 */
UPB_WIRE_TYPE_VARINT, /* INT32 */
UPB_WIRE_TYPE_64BIT, /* FIXED64 */
UPB_WIRE_TYPE_32BIT, /* FIXED32 */
UPB_WIRE_TYPE_VARINT, /* BOOL */
UPB_WIRE_TYPE_DELIMITED, /* STRING */
UPB_WIRE_TYPE_START_GROUP, /* GROUP */
UPB_WIRE_TYPE_DELIMITED, /* MESSAGE */
UPB_WIRE_TYPE_DELIMITED, /* BYTES */
UPB_WIRE_TYPE_VARINT, /* UINT32 */
UPB_WIRE_TYPE_VARINT, /* ENUM */
UPB_WIRE_TYPE_32BIT, /* SFIXED32 */
UPB_WIRE_TYPE_64BIT, /* SFIXED64 */
UPB_WIRE_TYPE_VARINT, /* SINT32 */
UPB_WIRE_TYPE_VARINT, /* SINT64 */
};
/* A basic branch-based decoder, uses 32-bit values to get good performance
* on 32-bit architectures (but performs well on 64-bits also).
* This scheme comes from the original Google Protobuf implementation
* (proto2). */
upb_decoderet upb_vdecode_max8_branch32(upb_decoderet r) {
upb_decoderet err = {NULL, 0};
const char *p = r.p;
uint32_t low = (uint32_t)r.val;
uint32_t high = 0;
uint32_t b;
b = *(p++); low |= (b & 0x7fU) << 14; if (!(b & 0x80)) goto done;
b = *(p++); low |= (b & 0x7fU) << 21; if (!(b & 0x80)) goto done;
b = *(p++); low |= (b & 0x7fU) << 28;
high = (b & 0x7fU) >> 4; if (!(b & 0x80)) goto done;
b = *(p++); high |= (b & 0x7fU) << 3; if (!(b & 0x80)) goto done;
b = *(p++); high |= (b & 0x7fU) << 10; if (!(b & 0x80)) goto done;
b = *(p++); high |= (b & 0x7fU) << 17; if (!(b & 0x80)) goto done;
b = *(p++); high |= (b & 0x7fU) << 24; if (!(b & 0x80)) goto done;
b = *(p++); high |= (b & 0x7fU) << 31; if (!(b & 0x80)) goto done;
return err;
done:
r.val = ((uint64_t)high << 32) | low;
r.p = p;
return r;
}
/* Like the previous, but uses 64-bit values. */
upb_decoderet upb_vdecode_max8_branch64(upb_decoderet r) {
const char *p = r.p;
uint64_t val = r.val;
uint64_t b;
upb_decoderet err = {NULL, 0};
b = *(p++); val |= (b & 0x7fU) << 14; if (!(b & 0x80)) goto done;
b = *(p++); val |= (b & 0x7fU) << 21; if (!(b & 0x80)) goto done;
b = *(p++); val |= (b & 0x7fU) << 28; if (!(b & 0x80)) goto done;
b = *(p++); val |= (b & 0x7fU) << 35; if (!(b & 0x80)) goto done;
b = *(p++); val |= (b & 0x7fU) << 42; if (!(b & 0x80)) goto done;
b = *(p++); val |= (b & 0x7fU) << 49; if (!(b & 0x80)) goto done;
b = *(p++); val |= (b & 0x7fU) << 56; if (!(b & 0x80)) goto done;
b = *(p++); val |= (b & 0x7fU) << 63; if (!(b & 0x80)) goto done;
return err;
done:
r.val = val;
r.p = p;
return r;
}

@ -1,164 +0,0 @@
/*
** A number of routines for varint manipulation (we keep them all around to
** have multiple approaches available for benchmarking).
*/
#ifndef UPB_VARINT_DECODER_H_
#define UPB_VARINT_DECODER_H_
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include "upb/upb.h"
#include "upb/port_def.inc"
#ifdef __cplusplus
extern "C" {
#endif
#define UPB_MAX_WIRE_TYPE 5
/* The maximum number of bytes that it takes to encode a 64-bit varint. */
#define UPB_PB_VARINT_MAX_LEN 10
/* Array of the "native" (ie. non-packed-repeated) wire type for the given a
* descriptor type (upb_descriptortype_t). */
extern const uint8_t upb_pb_native_wire_types[];
UPB_INLINE uint64_t byteswap64(uint64_t val) {
uint64_t byte = 0xff;
return (val & (byte << 56) >> 56)
| (val & (byte << 48) >> 40)
| (val & (byte << 40) >> 24)
| (val & (byte << 32) >> 8)
| (val & (byte << 24) << 8)
| (val & (byte << 16) << 24)
| (val & (byte << 8) << 40)
| (val & (byte << 0) << 56);
}
/* Zig-zag encoding/decoding **************************************************/
UPB_INLINE int32_t upb_zzdec_32(uint64_t _n) {
uint32_t n = (uint32_t)_n;
return (n >> 1) ^ -(int32_t)(n & 1);
}
UPB_INLINE int64_t upb_zzdec_64(uint64_t n) {
return (n >> 1) ^ -(int64_t)(n & 1);
}
UPB_INLINE uint32_t upb_zzenc_32(int32_t n) {
return ((uint32_t)n << 1) ^ (n >> 31);
}
UPB_INLINE uint64_t upb_zzenc_64(int64_t n) {
return ((uint64_t)n << 1) ^ (n >> 63);
}
/* Decoding *******************************************************************/
/* All decoding functions return this struct by value. */
typedef struct {
const char *p; /* NULL if the varint was unterminated. */
uint64_t val;
} upb_decoderet;
UPB_INLINE upb_decoderet upb_decoderet_make(const char *p, uint64_t val) {
upb_decoderet ret;
ret.p = p;
ret.val = val;
return ret;
}
upb_decoderet upb_vdecode_max8_branch32(upb_decoderet r);
upb_decoderet upb_vdecode_max8_branch64(upb_decoderet r);
/* Template for a function that checks the first two bytes with branching
* and dispatches 2-10 bytes with a separate function. Note that this may read
* up to 10 bytes, so it must not be used unless there are at least ten bytes
* left in the buffer! */
#define UPB_VARINT_DECODER_CHECK2(name, decode_max8_function) \
UPB_INLINE upb_decoderet upb_vdecode_check2_ ## name(const char *_p) { \
uint8_t *p = (uint8_t*)_p; \
upb_decoderet r; \
if ((*p & 0x80) == 0) { \
/* Common case: one-byte varint. */ \
return upb_decoderet_make(_p + 1, *p & 0x7fU); \
} \
r = upb_decoderet_make(_p + 2, (*p & 0x7fU) | ((*(p + 1) & 0x7fU) << 7)); \
if ((*(p + 1) & 0x80) == 0) { \
/* Two-byte varint. */ \
return r; \
} \
/* Longer varint, fallback to out-of-line function. */ \
return decode_max8_function(r); \
}
UPB_VARINT_DECODER_CHECK2(branch32, upb_vdecode_max8_branch32)
UPB_VARINT_DECODER_CHECK2(branch64, upb_vdecode_max8_branch64)
#undef UPB_VARINT_DECODER_CHECK2
/* Our canonical functions for decoding varints, based on the currently
* favored best-performing implementations. */
UPB_INLINE upb_decoderet upb_vdecode_fast(const char *p) {
if (sizeof(long) == 8)
return upb_vdecode_check2_branch64(p);
else
return upb_vdecode_check2_branch32(p);
}
/* Encoding *******************************************************************/
UPB_INLINE int upb_value_size(uint64_t val) {
#ifdef __GNUC__
/* 0-based, undef if val == 0. */
int high_bit = val ? 63 - __builtin_clzll(val) : 0;
#else
int high_bit = 0;
uint64_t tmp = val;
while(tmp >>= 1) high_bit++;
#endif
return val == 0 ? 1 : high_bit / 8 + 1;
}
/* Encodes a 64-bit varint into buf (which must be >=UPB_PB_VARINT_MAX_LEN
* bytes long), returning how many bytes were used.
*
* TODO: benchmark and optimize if necessary. */
UPB_INLINE size_t upb_vencode64(uint64_t val, char *buf) {
size_t i;
if (val == 0) { buf[0] = 0; return 1; }
i = 0;
while (val) {
uint8_t byte = val & 0x7fU;
val >>= 7;
if (val) byte |= 0x80U;
buf[i++] = byte;
}
return i;
}
UPB_INLINE size_t upb_varint_size(uint64_t val) {
char buf[UPB_PB_VARINT_MAX_LEN];
return upb_vencode64(val, buf);
}
/* Encodes a 32-bit varint, *not* sign-extended. */
UPB_INLINE uint64_t upb_vencode32(uint32_t val) {
char buf[UPB_PB_VARINT_MAX_LEN];
size_t bytes = upb_vencode64(val, buf);
uint64_t ret = 0;
UPB_ASSERT(bytes <= 5);
memcpy(&ret, buf, bytes);
ret = _upb_be_swap64(ret);
UPB_ASSERT(ret <= 0xffffffffffU);
return ret;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#include "upb/port_undef.inc"
#endif /* UPB_VARINT_DECODER_H_ */

@ -21,12 +21,10 @@
* This file is private and must not be included by users!
*/
#if !(__STDC_VERSION__ >= 199901L || __cplusplus >= 201103L)
#error upb requires C99 or C++11
#endif
#if (defined(_MSC_VER) && _MSC_VER < 1900)
#error upb requires MSVC >= 2015.
#if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
(defined(__cplusplus) && __cplusplus >= 201103L) || \
(defined(_MSC_VER) && _MSC_VER >= 1900))
#error upb requires C99 or C++11 or MSVC >= 2015.
#endif
#include <stdint.h>
@ -82,14 +80,17 @@
#define UPB_FORCEINLINE __inline__ __attribute__((always_inline))
#define UPB_NOINLINE __attribute__((noinline))
#define UPB_NORETURN __attribute__((__noreturn__))
#define UPB_PRINTF(str, first_vararg) __attribute__((format (printf, str, first_vararg)))
#elif defined(_MSC_VER)
#define UPB_NOINLINE
#define UPB_FORCEINLINE
#define UPB_NORETURN __declspec(noreturn)
#define UPB_PRINTF(str, first_vararg)
#else /* !defined(__GNUC__) */
#define UPB_FORCEINLINE
#define UPB_NOINLINE
#define UPB_NORETURN
#define UPB_PRINTF(str, first_vararg)
#endif
#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y))

@ -136,7 +136,7 @@ upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f) {
val.double_val = upb_fielddef_defaultdouble(f);
break;
case UPB_TYPE_BOOL:
val.double_val = upb_fielddef_defaultbool(f);
val.bool_val = upb_fielddef_defaultbool(f);
break;
case UPB_TYPE_STRING:
case UPB_TYPE_BYTES:
@ -361,6 +361,10 @@ bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val) {
return _upb_map_get(map, &key, map->key_size, val, map->val_size);
}
void upb_map_clear(upb_map *map) {
_upb_map_clear(map);
}
bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val,
upb_arena *arena) {
return _upb_map_set(map, &key, map->key_size, &val, map->val_size, arena);

@ -8,6 +8,10 @@
#include "upb/port_def.inc"
#ifdef __cplusplus
extern "C" {
#endif
typedef union {
bool bool_val;
float float_val;
@ -28,6 +32,8 @@ typedef union {
upb_array* array;
} upb_mutmsgval;
upb_msgval upb_fielddef_default(const upb_fielddef *f);
/** upb_msg *******************************************************************/
/* Creates a new message of the given type in the given arena. */
@ -163,6 +169,10 @@ upb_msgval upb_mapiter_value(const upb_map *map, size_t iter);
* iterator must not have been initialized const. */
void upb_mapiter_setvalue(upb_map *map, size_t iter, upb_msgval value);
#ifdef __cplusplus
} /* extern "C" */
#endif
#include "upb/port_undef.inc"
#endif /* UPB_REFLECTION_H_ */

@ -0,0 +1,13 @@
#ifndef UPB_REFLECTION_HPP_
#define UPB_REFLECTION_HPP_
#include "upb/reflection.h"
namespace upb {
typedef upb_msgval MessageValue;
} // namespace upb
#endif // UPB_REFLECTION_HPP_

@ -1,17 +0,0 @@
#include "upb/sink.h"
bool upb_bufsrc_putbuf(const char *buf, size_t len, upb_bytessink sink) {
void *subc;
bool ret;
upb_bufhandle handle = UPB_BUFHANDLE_INIT;
handle.buf = buf;
ret = upb_bytessink_start(sink, len, &subc);
if (ret && len != 0) {
ret = (upb_bytessink_putbuf(sink, subc, buf, len, &handle) >= len);
}
if (ret) {
ret = upb_bytessink_end(sink);
}
return ret;
}

@ -1,517 +0,0 @@
/*
** upb::Sink (upb_sink)
** upb::BytesSink (upb_bytessink)
**
** A upb_sink is an object that binds a upb_handlers object to some runtime
** state. It is the object that can actually receive data via the upb_handlers
** interface.
**
** Unlike upb_def and upb_handlers, upb_sink is never frozen, immutable, or
** thread-safe. You can create as many of them as you want, but each one may
** only be used in a single thread at a time.
**
** If we compare with class-based OOP, a you can think of a upb_def as an
** abstract base class, a upb_handlers as a concrete derived class, and a
** upb_sink as an object (class instance).
*/
#ifndef UPB_SINK_H
#define UPB_SINK_H
#include "upb/handlers.h"
#include "upb/port_def.inc"
#ifdef __cplusplus
namespace upb {
class BytesSink;
class Sink;
}
#endif
/* upb_sink *******************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
const upb_handlers *handlers;
void *closure;
} upb_sink;
#define PUTVAL(type, ctype) \
UPB_INLINE bool upb_sink_put##type(upb_sink s, upb_selector_t sel, \
ctype val) { \
typedef upb_##type##_handlerfunc functype; \
functype *func; \
const void *hd; \
if (!s.handlers) return true; \
func = (functype *)upb_handlers_gethandler(s.handlers, sel, &hd); \
if (!func) return true; \
return func(s.closure, hd, val); \
}
PUTVAL(int32, int32_t)
PUTVAL(int64, int64_t)
PUTVAL(uint32, uint32_t)
PUTVAL(uint64, uint64_t)
PUTVAL(float, float)
PUTVAL(double, double)
PUTVAL(bool, bool)
#undef PUTVAL
UPB_INLINE void upb_sink_reset(upb_sink *s, const upb_handlers *h, void *c) {
s->handlers = h;
s->closure = c;
}
UPB_INLINE size_t upb_sink_putstring(upb_sink s, upb_selector_t sel,
const char *buf, size_t n,
const upb_bufhandle *handle) {
typedef upb_string_handlerfunc func;
func *handler;
const void *hd;
if (!s.handlers) return n;
handler = (func *)upb_handlers_gethandler(s.handlers, sel, &hd);
if (!handler) return n;
return handler(s.closure, hd, buf, n, handle);
}
UPB_INLINE bool upb_sink_putunknown(upb_sink s, const char *buf, size_t n) {
typedef upb_unknown_handlerfunc func;
func *handler;
const void *hd;
if (!s.handlers) return true;
handler =
(func *)upb_handlers_gethandler(s.handlers, UPB_UNKNOWN_SELECTOR, &hd);
if (!handler) return n;
return handler(s.closure, hd, buf, n);
}
UPB_INLINE bool upb_sink_startmsg(upb_sink s) {
typedef upb_startmsg_handlerfunc func;
func *startmsg;
const void *hd;
if (!s.handlers) return true;
startmsg =
(func *)upb_handlers_gethandler(s.handlers, UPB_STARTMSG_SELECTOR, &hd);
if (!startmsg) return true;
return startmsg(s.closure, hd);
}
UPB_INLINE bool upb_sink_endmsg(upb_sink s, upb_status *status) {
typedef upb_endmsg_handlerfunc func;
func *endmsg;
const void *hd;
if (!s.handlers) return true;
endmsg =
(func *)upb_handlers_gethandler(s.handlers, UPB_ENDMSG_SELECTOR, &hd);
if (!endmsg) return true;
return endmsg(s.closure, hd, status);
}
UPB_INLINE bool upb_sink_startseq(upb_sink s, upb_selector_t sel,
upb_sink *sub) {
typedef upb_startfield_handlerfunc func;
func *startseq;
const void *hd;
sub->closure = s.closure;
sub->handlers = s.handlers;
if (!s.handlers) return true;
startseq = (func*)upb_handlers_gethandler(s.handlers, sel, &hd);
if (!startseq) return true;
sub->closure = startseq(s.closure, hd);
return sub->closure ? true : false;
}
UPB_INLINE bool upb_sink_endseq(upb_sink s, upb_selector_t sel) {
typedef upb_endfield_handlerfunc func;
func *endseq;
const void *hd;
if (!s.handlers) return true;
endseq = (func*)upb_handlers_gethandler(s.handlers, sel, &hd);
if (!endseq) return true;
return endseq(s.closure, hd);
}
UPB_INLINE bool upb_sink_startstr(upb_sink s, upb_selector_t sel,
size_t size_hint, upb_sink *sub) {
typedef upb_startstr_handlerfunc func;
func *startstr;
const void *hd;
sub->closure = s.closure;
sub->handlers = s.handlers;
if (!s.handlers) return true;
startstr = (func*)upb_handlers_gethandler(s.handlers, sel, &hd);
if (!startstr) return true;
sub->closure = startstr(s.closure, hd, size_hint);
return sub->closure ? true : false;
}
UPB_INLINE bool upb_sink_endstr(upb_sink s, upb_selector_t sel) {
typedef upb_endfield_handlerfunc func;
func *endstr;
const void *hd;
if (!s.handlers) return true;
endstr = (func*)upb_handlers_gethandler(s.handlers, sel, &hd);
if (!endstr) return true;
return endstr(s.closure, hd);
}
UPB_INLINE bool upb_sink_startsubmsg(upb_sink s, upb_selector_t sel,
upb_sink *sub) {
typedef upb_startfield_handlerfunc func;
func *startsubmsg;
const void *hd;
sub->closure = s.closure;
if (!s.handlers) {
sub->handlers = NULL;
return true;
}
sub->handlers = upb_handlers_getsubhandlers_sel(s.handlers, sel);
startsubmsg = (func*)upb_handlers_gethandler(s.handlers, sel, &hd);
if (!startsubmsg) return true;
sub->closure = startsubmsg(s.closure, hd);
return sub->closure ? true : false;
}
UPB_INLINE bool upb_sink_endsubmsg(upb_sink s, upb_sink sub,
upb_selector_t sel) {
typedef upb_endfield_handlerfunc func;
func *endsubmsg;
const void *hd;
if (!s.handlers) return true;
endsubmsg = (func*)upb_handlers_gethandler(s.handlers, sel, &hd);
if (!endsubmsg) return true;
return endsubmsg(sub.closure, hd);
}
#ifdef __cplusplus
} /* extern "C" */
/* A upb::Sink is an object that binds a upb::Handlers object to some runtime
* state. It represents an endpoint to which data can be sent.
*
* TODO(haberman): right now all of these functions take selectors. Should they
* take selectorbase instead?
*
* ie. instead of calling:
* sink->StartString(FOO_FIELD_START_STRING, ...)
* a selector base would let you say:
* sink->StartString(FOO_FIELD, ...)
*
* This would make call sites a little nicer and require emitting fewer selector
* definitions in .h files.
*
* But the current scheme has the benefit that you can retrieve a function
* pointer for any handler with handlers->GetHandler(selector), without having
* to have a separate GetHandler() function for each handler type. The JIT
* compiler uses this. To accommodate we'd have to expose a separate
* GetHandler() for every handler type.
*
* Also to ponder: selectors right now are independent of a specific Handlers
* instance. In other words, they allocate a number to every possible handler
* that *could* be registered, without knowing anything about what handlers
* *are* registered. That means that using selectors as table offsets prohibits
* us from compacting the handler table at Freeze() time. If the table is very
* sparse, this could be wasteful.
*
* Having another selector-like thing that is specific to a Handlers instance
* would allow this compacting, but then it would be impossible to write code
* ahead-of-time that can be bound to any Handlers instance at runtime. For
* example, a .proto file parser written as straight C will not know what
* Handlers it will be bound to, so when it calls sink->StartString() what
* selector will it pass? It needs a selector like we have today, that is
* independent of any particular upb::Handlers.
*
* Is there a way then to allow Handlers table compaction? */
class upb::Sink {
public:
/* Constructor with no initialization; must be Reset() before use. */
Sink() {}
Sink(const Sink&) = default;
Sink& operator=(const Sink&) = default;
Sink(const upb_sink& sink) : sink_(sink) {}
Sink &operator=(const upb_sink &sink) {
sink_ = sink;
return *this;
}
upb_sink sink() { return sink_; }
/* Constructs a new sink for the given frozen handlers and closure.
*
* TODO: once the Handlers know the expected closure type, verify that T
* matches it. */
template <class T> Sink(const upb_handlers* handlers, T* closure) {
Reset(handlers, closure);
}
upb_sink* ptr() { return &sink_; }
/* Resets the value of the sink. */
template <class T> void Reset(const upb_handlers* handlers, T* closure) {
upb_sink_reset(&sink_, handlers, closure);
}
/* Returns the top-level object that is bound to this sink.
*
* TODO: once the Handlers know the expected closure type, verify that T
* matches it. */
template <class T> T* GetObject() const {
return static_cast<T*>(sink_.closure);
}
/* Functions for pushing data into the sink.
*
* These return false if processing should stop (either due to error or just
* to suspend).
*
* These may not be called from within one of the same sink's handlers (in
* other words, handlers are not re-entrant). */
/* Should be called at the start and end of every message; both the top-level
* message and submessages. This means that submessages should use the
* following sequence:
* sink->StartSubMessage(startsubmsg_selector);
* sink->StartMessage();
* // ...
* sink->EndMessage(&status);
* sink->EndSubMessage(endsubmsg_selector); */
bool StartMessage() { return upb_sink_startmsg(sink_); }
bool EndMessage(upb_status *status) {
return upb_sink_endmsg(sink_, status);
}
/* Putting of individual values. These work for both repeated and
* non-repeated fields, but for repeated fields you must wrap them in
* calls to StartSequence()/EndSequence(). */
bool PutInt32(HandlersPtr::Selector s, int32_t val) {
return upb_sink_putint32(sink_, s, val);
}
bool PutInt64(HandlersPtr::Selector s, int64_t val) {
return upb_sink_putint64(sink_, s, val);
}
bool PutUInt32(HandlersPtr::Selector s, uint32_t val) {
return upb_sink_putuint32(sink_, s, val);
}
bool PutUInt64(HandlersPtr::Selector s, uint64_t val) {
return upb_sink_putuint64(sink_, s, val);
}
bool PutFloat(HandlersPtr::Selector s, float val) {
return upb_sink_putfloat(sink_, s, val);
}
bool PutDouble(HandlersPtr::Selector s, double val) {
return upb_sink_putdouble(sink_, s, val);
}
bool PutBool(HandlersPtr::Selector s, bool val) {
return upb_sink_putbool(sink_, s, val);
}
/* Putting of string/bytes values. Each string can consist of zero or more
* non-contiguous buffers of data.
*
* For StartString(), the function will write a sink for the string to "sub."
* The sub-sink must be used for any/all PutStringBuffer() calls. */
bool StartString(HandlersPtr::Selector s, size_t size_hint, Sink* sub) {
upb_sink sub_c;
bool ret = upb_sink_startstr(sink_, s, size_hint, &sub_c);
*sub = sub_c;
return ret;
}
size_t PutStringBuffer(HandlersPtr::Selector s, const char *buf, size_t len,
const upb_bufhandle *handle) {
return upb_sink_putstring(sink_, s, buf, len, handle);
}
bool EndString(HandlersPtr::Selector s) {
return upb_sink_endstr(sink_, s);
}
/* For submessage fields.
*
* For StartSubMessage(), the function will write a sink for the string to
* "sub." The sub-sink must be used for any/all handlers called within the
* submessage. */
bool StartSubMessage(HandlersPtr::Selector s, Sink* sub) {
upb_sink sub_c;
bool ret = upb_sink_startsubmsg(sink_, s, &sub_c);
*sub = sub_c;
return ret;
}
bool EndSubMessage(HandlersPtr::Selector s, Sink sub) {
return upb_sink_endsubmsg(sink_, sub.sink_, s);
}
/* For repeated fields of any type, the sequence of values must be wrapped in
* these calls.
*
* For StartSequence(), the function will write a sink for the string to
* "sub." The sub-sink must be used for any/all handlers called within the
* sequence. */
bool StartSequence(HandlersPtr::Selector s, Sink* sub) {
upb_sink sub_c;
bool ret = upb_sink_startseq(sink_, s, &sub_c);
*sub = sub_c;
return ret;
}
bool EndSequence(HandlersPtr::Selector s) {
return upb_sink_endseq(sink_, s);
}
/* Copy and assign specifically allowed.
* We don't even bother making these members private because so many
* functions need them and this is mainly just a dumb data container anyway.
*/
private:
upb_sink sink_;
};
#endif /* __cplusplus */
/* upb_bytessink **************************************************************/
typedef struct {
const upb_byteshandler *handler;
void *closure;
} upb_bytessink ;
UPB_INLINE void upb_bytessink_reset(upb_bytessink* s, const upb_byteshandler *h,
void *closure) {
s->handler = h;
s->closure = closure;
}
UPB_INLINE bool upb_bytessink_start(upb_bytessink s, size_t size_hint,
void **subc) {
typedef upb_startstr_handlerfunc func;
func *start;
*subc = s.closure;
if (!s.handler) return true;
start = (func *)s.handler->table[UPB_STARTSTR_SELECTOR].func;
if (!start) return true;
*subc = start(s.closure,
s.handler->table[UPB_STARTSTR_SELECTOR].attr.handler_data,
size_hint);
return *subc != NULL;
}
UPB_INLINE size_t upb_bytessink_putbuf(upb_bytessink s, void *subc,
const char *buf, size_t size,
const upb_bufhandle* handle) {
typedef upb_string_handlerfunc func;
func *putbuf;
if (!s.handler) return true;
putbuf = (func *)s.handler->table[UPB_STRING_SELECTOR].func;
if (!putbuf) return true;
return putbuf(subc, s.handler->table[UPB_STRING_SELECTOR].attr.handler_data,
buf, size, handle);
}
UPB_INLINE bool upb_bytessink_end(upb_bytessink s) {
typedef upb_endfield_handlerfunc func;
func *end;
if (!s.handler) return true;
end = (func *)s.handler->table[UPB_ENDSTR_SELECTOR].func;
if (!end) return true;
return end(s.closure,
s.handler->table[UPB_ENDSTR_SELECTOR].attr.handler_data);
}
#ifdef __cplusplus
class upb::BytesSink {
public:
BytesSink() {}
BytesSink(const BytesSink&) = default;
BytesSink& operator=(const BytesSink&) = default;
BytesSink(const upb_bytessink& sink) : sink_(sink) {}
BytesSink &operator=(const upb_bytessink &sink) {
sink_ = sink;
return *this;
}
upb_bytessink sink() { return sink_; }
/* Constructs a new sink for the given frozen handlers and closure.
*
* TODO(haberman): once the Handlers know the expected closure type, verify
* that T matches it. */
template <class T> BytesSink(const upb_byteshandler* handler, T* closure) {
upb_bytessink_reset(sink_, handler, closure);
}
/* Resets the value of the sink. */
template <class T> void Reset(const upb_byteshandler* handler, T* closure) {
upb_bytessink_reset(&sink_, handler, closure);
}
bool Start(size_t size_hint, void **subc) {
return upb_bytessink_start(sink_, size_hint, subc);
}
size_t PutBuffer(void *subc, const char *buf, size_t len,
const upb_bufhandle *handle) {
return upb_bytessink_putbuf(sink_, subc, buf, len, handle);
}
bool End() {
return upb_bytessink_end(sink_);
}
private:
upb_bytessink sink_;
};
#endif /* __cplusplus */
/* upb_bufsrc *****************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
bool upb_bufsrc_putbuf(const char *buf, size_t len, upb_bytessink sink);
#ifdef __cplusplus
} /* extern "C" */
namespace upb {
template <class T> bool PutBuffer(const T& str, BytesSink sink) {
return upb_bufsrc_putbuf(str.data(), str.size(), sink.sink());
}
}
#endif /* __cplusplus */
#include "upb/port_undef.inc"
#endif

@ -27,6 +27,12 @@ static const double MIN_DENSITY = 0.1;
bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; }
static upb_value _upb_value_val(uint64_t val) {
upb_value ret;
_upb_value_setval(&ret, val);
return ret;
}
int log2ceil(uint64_t v) {
int ret = 0;
bool pow2 = is_pow2(v);
@ -35,11 +41,11 @@ int log2ceil(uint64_t v) {
return UPB_MIN(UPB_MAXARRSIZE, ret);
}
char *upb_strdup(const char *s, upb_alloc *a) {
char *upb_strdup(const char *s, upb_arena *a) {
return upb_strdup2(s, strlen(s), a);
}
char *upb_strdup2(const char *s, size_t len, upb_alloc *a) {
char *upb_strdup2(const char *s, size_t len, upb_arena *a) {
size_t n;
char *p;
@ -48,7 +54,7 @@ char *upb_strdup2(const char *s, size_t len, upb_alloc *a) {
/* Always null-terminate, even if binary data; but don't rely on the input to
* have a null-terminating byte since it may be a raw binary buffer. */
n = len + 1;
p = upb_malloc(a, n);
p = upb_arena_malloc(a, n);
if (p) {
memcpy(p, s, len);
p[len] = 0;
@ -83,16 +89,24 @@ typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2);
/* Base table (shared code) ***************************************************/
/* For when we need to cast away const. */
static upb_tabent *mutable_entries(upb_table *t) {
return (upb_tabent*)t->entries;
static uint32_t upb_inthash(uintptr_t key) {
return (uint32_t)key;
}
static const upb_tabent *upb_getentry(const upb_table *t, uint32_t hash) {
return t->entries + (hash & t->mask);
}
static bool upb_arrhas(upb_tabval key) {
return key.val != (uint64_t)-1;
}
static bool isfull(upb_table *t) {
return t->count == t->max_count;
}
static bool init(upb_table *t, uint8_t size_lg2, upb_alloc *a) {
static bool init(upb_table *t, uint8_t size_lg2, upb_arena *a) {
size_t bytes;
t->count = 0;
@ -101,21 +115,17 @@ static bool init(upb_table *t, uint8_t size_lg2, upb_alloc *a) {
t->max_count = upb_table_size(t) * MAX_LOAD;
bytes = upb_table_size(t) * sizeof(upb_tabent);
if (bytes > 0) {
t->entries = upb_malloc(a, bytes);
t->entries = upb_arena_malloc(a, bytes);
if (!t->entries) return false;
memset(mutable_entries(t), 0, bytes);
memset(t->entries, 0, bytes);
} else {
t->entries = NULL;
}
return true;
}
static void uninit(upb_table *t, upb_alloc *a) {
upb_free(a, mutable_entries(t));
}
static upb_tabent *emptyent(upb_table *t, upb_tabent *e) {
upb_tabent *begin = mutable_entries(t);
upb_tabent *begin = t->entries;
upb_tabent *end = begin + upb_table_size(t);
for (e = e + 1; e < end; e++) {
if (upb_tabent_isempty(e)) return e;
@ -184,7 +194,7 @@ static void insert(upb_table *t, lookupkey_t key, upb_tabkey tabkey,
/* Head of collider's chain. */
upb_tabent *chain = getentry_mutable(t, hashfunc(mainpos_e->key));
if (chain == mainpos_e) {
/* Existing ent is in its main posisiton (it has the same hash as us, and
/* Existing ent is in its main position (it has the same hash as us, and
* is the head of our chain). Insert to new ent and append to this chain. */
new_e->next = mainpos_e->next;
mainpos_e->next = new_e;
@ -265,9 +275,9 @@ static size_t begin(const upb_table *t) {
/* A simple "subclass" of upb_table that only adds a hash function for strings. */
static upb_tabkey strcopy(lookupkey_t k2, upb_alloc *a) {
static upb_tabkey strcopy(lookupkey_t k2, upb_arena *a) {
uint32_t len = (uint32_t) k2.str.len;
char *str = upb_malloc(a, k2.str.len + sizeof(uint32_t) + 1);
char *str = upb_arena_malloc(a, k2.str.len + sizeof(uint32_t) + 1);
if (str == NULL) return 0;
memcpy(str, &len, sizeof(uint32_t));
if (k2.str.len) memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len);
@ -291,9 +301,7 @@ static bool streql(upb_tabkey k1, lookupkey_t k2) {
return len == k2.str.len && (len == 0 || memcmp(str, k2.str.str, len) == 0);
}
bool upb_strtable_init2(upb_strtable *t, upb_ctype_t ctype,
size_t expected_size, upb_alloc *a) {
UPB_UNUSED(ctype); /* TODO(haberman): rm */
bool upb_strtable_init(upb_strtable *t, size_t expected_size, upb_arena *a) {
// Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2 denominator.
size_t need_entries = (expected_size + 1) * 1204 / 1024;
UPB_ASSERT(need_entries >= expected_size * 0.85);
@ -307,14 +315,7 @@ void upb_strtable_clear(upb_strtable *t) {
memset((char*)t->t.entries, 0, bytes);
}
void upb_strtable_uninit2(upb_strtable *t, upb_alloc *a) {
size_t i;
for (i = 0; i < upb_table_size(&t->t); i++)
upb_free(a, (void*)t->t.entries[i].key);
uninit(&t->t, a);
}
bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a) {
bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_arena *a) {
upb_strtable new_table;
upb_strtable_iter i;
@ -323,17 +324,15 @@ bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a) {
upb_strtable_begin(&i, t);
for ( ; !upb_strtable_done(&i); upb_strtable_next(&i)) {
upb_strview key = upb_strtable_iter_key(&i);
upb_strtable_insert3(
&new_table, key.data, key.size,
upb_strtable_iter_value(&i), a);
upb_strtable_insert(&new_table, key.data, key.size,
upb_strtable_iter_value(&i), a);
}
upb_strtable_uninit2(t, a);
*t = new_table;
return true;
}
bool upb_strtable_insert3(upb_strtable *t, const char *k, size_t len,
upb_value v, upb_alloc *a) {
bool upb_strtable_insert(upb_strtable *t, const char *k, size_t len,
upb_value v, upb_arena *a) {
lookupkey_t key;
upb_tabkey tabkey;
uint32_t hash;
@ -360,19 +359,11 @@ bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len,
return lookup(&t->t, strkey2(key, len), v, hash, &streql);
}
bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len,
upb_value *val, upb_alloc *alloc) {
bool upb_strtable_remove(upb_strtable *t, const char *key, size_t len,
upb_value *val) {
uint32_t hash = table_hash(key, len);
upb_tabkey tabkey;
if (rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql)) {
if (alloc) {
/* Arena-based allocs don't need to free and won't pass this. */
upb_free(alloc, (void*)tabkey);
}
return true;
} else {
return false;
}
return rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql);
}
/* Iteration */
@ -470,7 +461,7 @@ static void check(upb_inttable *t) {
}
bool upb_inttable_sizedinit(upb_inttable *t, size_t asize, int hsize_lg2,
upb_alloc *a) {
upb_arena *a) {
size_t array_bytes;
if (!init(&t->t, hsize_lg2, a)) return false;
@ -479,9 +470,8 @@ bool upb_inttable_sizedinit(upb_inttable *t, size_t asize, int hsize_lg2,
t->array_size = UPB_MAX(1, asize);
t->array_count = 0;
array_bytes = t->array_size * sizeof(upb_value);
t->array = upb_malloc(a, array_bytes);
t->array = upb_arena_malloc(a, array_bytes);
if (!t->array) {
uninit(&t->t, a);
return false;
}
memset(mutable_array(t), 0xff, array_bytes);
@ -489,18 +479,12 @@ bool upb_inttable_sizedinit(upb_inttable *t, size_t asize, int hsize_lg2,
return true;
}
bool upb_inttable_init2(upb_inttable *t, upb_ctype_t ctype, upb_alloc *a) {
UPB_UNUSED(ctype); /* TODO(haberman): rm */
bool upb_inttable_init(upb_inttable *t, upb_arena *a) {
return upb_inttable_sizedinit(t, 0, 4, a);
}
void upb_inttable_uninit2(upb_inttable *t, upb_alloc *a) {
uninit(&t->t, a);
upb_free(a, mutable_array(t));
}
bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val,
upb_alloc *a) {
bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val,
upb_arena *a) {
upb_tabval tabval;
tabval.val = val.val;
UPB_ASSERT(upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */
@ -531,7 +515,6 @@ bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val,
UPB_ASSERT(t->t.count == new_table.count);
uninit(&t->t, a);
t->t = new_table;
}
insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql);
@ -575,21 +558,7 @@ bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) {
return success;
}
bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val,
upb_alloc *a) {
return upb_inttable_insert2(t, (uintptr_t)key, val, a);
}
bool upb_inttable_lookupptr(const upb_inttable *t, const void *key,
upb_value *v) {
return upb_inttable_lookup(t, (uintptr_t)key, v);
}
bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val) {
return upb_inttable_remove(t, (uintptr_t)key, val);
}
void upb_inttable_compact2(upb_inttable *t, upb_alloc *a) {
void upb_inttable_compact(upb_inttable *t, upb_arena *a) {
/* A power-of-two histogram of the table keys. */
size_t counts[UPB_MAXARRSIZE + 1] = {0};
@ -637,12 +606,11 @@ void upb_inttable_compact2(upb_inttable *t, upb_alloc *a) {
upb_inttable_begin(&i, t);
for (; !upb_inttable_done(&i); upb_inttable_next(&i)) {
uintptr_t k = upb_inttable_iter_key(&i);
upb_inttable_insert2(&new_t, k, upb_inttable_iter_value(&i), a);
upb_inttable_insert(&new_t, k, upb_inttable_iter_value(&i), a);
}
UPB_ASSERT(new_t.array_size == arr_size);
UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2);
}
upb_inttable_uninit2(t, a);
*t = new_t;
}

@ -33,47 +33,20 @@ extern "C" {
/* upb_value ******************************************************************/
/* A tagged union (stored untagged inside the table) so that we can check that
* clients calling table accessors are correctly typed without having to have
* an explosion of accessors. */
typedef enum {
UPB_CTYPE_INT32 = 1,
UPB_CTYPE_INT64 = 2,
UPB_CTYPE_UINT32 = 3,
UPB_CTYPE_UINT64 = 4,
UPB_CTYPE_BOOL = 5,
UPB_CTYPE_CSTR = 6,
UPB_CTYPE_PTR = 7,
UPB_CTYPE_CONSTPTR = 8,
UPB_CTYPE_FPTR = 9,
UPB_CTYPE_FLOAT = 10,
UPB_CTYPE_DOUBLE = 11
} upb_ctype_t;
typedef struct {
uint64_t val;
} upb_value;
/* Like strdup(), which isn't always available since it's not ANSI C. */
char *upb_strdup(const char *s, upb_alloc *a);
char *upb_strdup(const char *s, upb_arena *a);
/* Variant that works with a length-delimited rather than NULL-delimited string,
* as supported by strtable. */
char *upb_strdup2(const char *s, size_t len, upb_alloc *a);
UPB_INLINE char *upb_gstrdup(const char *s) {
return upb_strdup(s, &upb_alloc_global);
}
char *upb_strdup2(const char *s, size_t len, upb_arena *a);
UPB_INLINE void _upb_value_setval(upb_value *v, uint64_t val) {
v->val = val;
}
UPB_INLINE upb_value _upb_value_val(uint64_t val) {
upb_value ret;
_upb_value_setval(&ret, val);
return ret;
}
/* For each value ctype, define the following set of functions:
*
* // Get/set an int32 from a upb_value.
@ -147,10 +120,17 @@ UPB_INLINE char *upb_tabstr(upb_tabkey key, uint32_t *len) {
return mem + sizeof(*len);
}
UPB_INLINE upb_strview upb_tabstrview(upb_tabkey key) {
upb_strview ret;
uint32_t len;
ret.data = upb_tabstr(key, &len);
ret.size = len;
return ret;
}
/* upb_tabval *****************************************************************/
typedef struct {
typedef struct upb_tabval {
uint64_t val;
} upb_tabval;
@ -174,14 +154,7 @@ typedef struct {
uint32_t mask; /* Mask to turn hash value -> bucket. */
uint32_t max_count; /* Max count before we hit our load limit. */
uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */
/* Hash table entries.
* Making this const isn't entirely accurate; what we really want is for it to
* have the same const-ness as the table it's inside. But there's no way to
* declare that in C. So we have to make it const so that we can statically
* initialize const hash tables. Then we cast away const when we have to.
*/
const upb_tabent *entries;
upb_tabent *entries;
} upb_table;
typedef struct {
@ -195,8 +168,6 @@ typedef struct {
size_t array_count; /* Array part number of elements. */
} upb_inttable;
#define UPB_ARRAY_EMPTYENT -1
UPB_INLINE size_t upb_table_size(const upb_table *t) {
if (t->size_lg2 == 0)
return 0;
@ -209,48 +180,10 @@ UPB_INLINE bool upb_tabent_isempty(const upb_tabent *e) {
return e->key == 0;
}
/* Used by some of the unit tests for generic hashing functionality. */
uint32_t upb_murmur_hash2(const void * key, size_t len, uint32_t seed);
UPB_INLINE uintptr_t upb_intkey(uintptr_t key) {
return key;
}
UPB_INLINE uint32_t upb_inthash(uintptr_t key) {
return (uint32_t)key;
}
static const upb_tabent *upb_getentry(const upb_table *t, uint32_t hash) {
return t->entries + (hash & t->mask);
}
UPB_INLINE bool upb_arrhas(upb_tabval key) {
return key.val != (uint64_t)-1;
}
/* Initialize and uninitialize a table, respectively. If memory allocation
* failed, false is returned that the table is uninitialized. */
bool upb_inttable_init2(upb_inttable *table, upb_ctype_t ctype, upb_alloc *a);
bool upb_strtable_init2(upb_strtable *table, upb_ctype_t ctype,
size_t expected_size, upb_alloc *a);
void upb_inttable_uninit2(upb_inttable *table, upb_alloc *a);
void upb_strtable_uninit2(upb_strtable *table, upb_alloc *a);
UPB_INLINE bool upb_inttable_init(upb_inttable *table, upb_ctype_t ctype) {
return upb_inttable_init2(table, ctype, &upb_alloc_global);
}
UPB_INLINE bool upb_strtable_init(upb_strtable *table, upb_ctype_t ctype) {
return upb_strtable_init2(table, ctype, 4, &upb_alloc_global);
}
UPB_INLINE void upb_inttable_uninit(upb_inttable *table) {
upb_inttable_uninit2(table, &upb_alloc_global);
}
UPB_INLINE void upb_strtable_uninit(upb_strtable *table) {
upb_strtable_uninit2(table, &upb_alloc_global);
}
bool upb_inttable_init(upb_inttable *table, upb_arena *a);
bool upb_strtable_init(upb_strtable *table, size_t expected_size, upb_arena *a);
/* Returns the number of values in the table. */
size_t upb_inttable_count(const upb_inttable *t);
@ -258,12 +191,6 @@ UPB_INLINE size_t upb_strtable_count(const upb_strtable *t) {
return t->t.count;
}
void upb_inttable_packedsize(const upb_inttable *t, size_t *size);
void upb_strtable_packedsize(const upb_strtable *t, size_t *size);
upb_inttable *upb_inttable_pack(const upb_inttable *t, void *p, size_t *ofs,
size_t size);
upb_strtable *upb_strtable_pack(const upb_strtable *t, void *p, size_t *ofs,
size_t size);
void upb_strtable_clear(upb_strtable *t);
/* Inserts the given key into the hashtable with the given value. The key must
@ -273,26 +200,10 @@ void upb_strtable_clear(upb_strtable *t);
*
* If a table resize was required but memory allocation failed, false is
* returned and the table is unchanged. */
bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val,
upb_alloc *a);
bool upb_strtable_insert3(upb_strtable *t, const char *key, size_t len,
upb_value val, upb_alloc *a);
UPB_INLINE bool upb_inttable_insert(upb_inttable *t, uintptr_t key,
upb_value val) {
return upb_inttable_insert2(t, key, val, &upb_alloc_global);
}
UPB_INLINE bool upb_strtable_insert2(upb_strtable *t, const char *key,
size_t len, upb_value val) {
return upb_strtable_insert3(t, key, len, val, &upb_alloc_global);
}
/* For NULL-terminated strings. */
UPB_INLINE bool upb_strtable_insert(upb_strtable *t, const char *key,
upb_value val) {
return upb_strtable_insert2(t, key, strlen(key), val);
}
bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val,
upb_arena *a);
bool upb_strtable_insert(upb_strtable *t, const char *key, size_t len,
upb_value val, upb_arena *a);
/* Looks up key in this table, returning "true" if the key was found.
* If v is non-NULL, copies the value for this key into *v. */
@ -309,74 +220,21 @@ UPB_INLINE bool upb_strtable_lookup(const upb_strtable *t, const char *key,
/* Removes an item from the table. Returns true if the remove was successful,
* and stores the removed item in *val if non-NULL. */
bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val);
bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len,
upb_value *val, upb_alloc *alloc);
UPB_INLINE bool upb_strtable_remove2(upb_strtable *t, const char *key,
size_t len, upb_value *val) {
return upb_strtable_remove3(t, key, len, val, &upb_alloc_global);
}
/* For NULL-terminated strings. */
UPB_INLINE bool upb_strtable_remove(upb_strtable *t, const char *key,
upb_value *v) {
return upb_strtable_remove2(t, key, strlen(key), v);
}
bool upb_strtable_remove(upb_strtable *t, const char *key, size_t len,
upb_value *val);
/* Updates an existing entry in an inttable. If the entry does not exist,
* returns false and does nothing. Unlike insert/remove, this does not
* invalidate iterators. */
bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val);
/* Convenience routines for inttables with pointer keys. */
bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val,
upb_alloc *a);
bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val);
bool upb_inttable_lookupptr(
const upb_inttable *t, const void *key, upb_value *val);
UPB_INLINE bool upb_inttable_insertptr(upb_inttable *t, const void *key,
upb_value val) {
return upb_inttable_insertptr2(t, key, val, &upb_alloc_global);
}
/* Optimizes the table for the current set of entries, for both memory use and
* lookup time. Client should call this after all entries have been inserted;
* inserting more entries is legal, but will likely require a table resize. */
void upb_inttable_compact2(upb_inttable *t, upb_alloc *a);
UPB_INLINE void upb_inttable_compact(upb_inttable *t) {
upb_inttable_compact2(t, &upb_alloc_global);
}
/* A special-case inlinable version of the lookup routine for 32-bit
* integers. */
UPB_INLINE bool upb_inttable_lookup32(const upb_inttable *t, uint32_t key,
upb_value *v) {
*v = upb_value_int32(0); /* Silence compiler warnings. */
if (key < t->array_size) {
upb_tabval arrval = t->array[key];
if (upb_arrhas(arrval)) {
_upb_value_setval(v, arrval.val);
return true;
} else {
return false;
}
} else {
const upb_tabent *e;
if (t->t.entries == NULL) return false;
for (e = upb_getentry(&t->t, upb_inthash(key)); true; e = e->next) {
if ((uint32_t)e->key == key) {
_upb_value_setval(v, e->val.val);
return true;
}
if (e->next == NULL) return false;
}
}
}
void upb_inttable_compact(upb_inttable *t, upb_arena *a);
/* Exposed for testing only. */
bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a);
bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_arena *a);
/* Iterators ******************************************************************/

@ -17,6 +17,7 @@ typedef struct {
int indent_depth;
int options;
const upb_symtab *ext_pool;
_upb_mapsorter sorter;
} txtenc;
static void txtenc_msg(txtenc *e, const upb_msg *msg, const upb_msgdef *m);
@ -187,6 +188,25 @@ static void txtenc_array(txtenc *e, const upb_array *arr,
}
}
static void txtenc_mapentry(txtenc *e, upb_msgval key, upb_msgval val,
const upb_fielddef *f) {
const upb_msgdef *entry = upb_fielddef_msgsubdef(f);
const upb_fielddef *key_f = upb_msgdef_field(entry, 0);
const upb_fielddef *val_f = upb_msgdef_field(entry, 1);
txtenc_indent(e);
txtenc_printf(e, "%s: {", upb_fielddef_name(f));
txtenc_endfield(e);
e->indent_depth++;
txtenc_field(e, key, key_f);
txtenc_field(e, val, val_f);
e->indent_depth--;
txtenc_indent(e);
txtenc_putstr(e, "}");
txtenc_endfield(e);
}
/*
* Maps print as messages of key/value, etc.
*
@ -200,27 +220,28 @@ static void txtenc_array(txtenc *e, const upb_array *arr,
* }
*/
static void txtenc_map(txtenc *e, const upb_map *map, const upb_fielddef *f) {
const upb_msgdef *entry = upb_fielddef_msgsubdef(f);
const upb_fielddef *key_f = upb_msgdef_itof(entry, 1);
const upb_fielddef *val_f = upb_msgdef_itof(entry, 2);
size_t iter = UPB_MAP_BEGIN;
while (upb_mapiter_next(map, &iter)) {
upb_msgval key = upb_mapiter_key(map, iter);
upb_msgval val = upb_mapiter_value(map, iter);
txtenc_indent(e);
txtenc_printf(e, "%s: {", upb_fielddef_name(f));
txtenc_endfield(e);
e->indent_depth++;
txtenc_field(e, key, key_f);
txtenc_field(e, val, val_f);
e->indent_depth--;
txtenc_indent(e);
txtenc_putstr(e, "}");
txtenc_endfield(e);
if (e->options & UPB_TXTENC_NOSORT) {
size_t iter = UPB_MAP_BEGIN;
while (upb_mapiter_next(map, &iter)) {
upb_msgval key = upb_mapiter_key(map, iter);
upb_msgval val = upb_mapiter_value(map, iter);
txtenc_mapentry(e, key, val, f);
}
} else {
const upb_msgdef *entry = upb_fielddef_msgsubdef(f);
const upb_fielddef *key_f = upb_msgdef_field(entry, 0);
_upb_sortedmap sorted;
upb_map_entry ent;
_upb_mapsorter_pushmap(&e->sorter, upb_fielddef_descriptortype(key_f), map,
&sorted);
while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) {
upb_msgval key, val;
memcpy(&key, &ent.k, sizeof(key));
memcpy(&val, &ent.v, sizeof(val));
txtenc_mapentry(e, key, val, f);
}
_upb_mapsorter_popmap(&e->sorter, &sorted);
}
}
@ -392,7 +413,9 @@ size_t upb_text_encode(const upb_msg *msg, const upb_msgdef *m,
e.indent_depth = 0;
e.options = options;
e.ext_pool = ext_pool;
_upb_mapsorter_init(&e.sorter);
txtenc_msg(&e, msg, m);
_upb_mapsorter_destroy(&e.sorter);
return txtenc_nullz(&e, size);
}

@ -13,7 +13,10 @@ enum {
UPB_TXTENC_SINGLELINE = 1,
/* When set, unknown fields are not printed. */
UPB_TXTENC_SKIPUNKNOWN = 2
UPB_TXTENC_SKIPUNKNOWN = 2,
/* When set, maps are *not* sorted (this avoids allocating tmp mem). */
UPB_TXTENC_NOSORT = 4
};
/* Encodes the given |msg| to text format. The message's reflection is given in

@ -33,9 +33,12 @@ bool upb_ok(const upb_status *status);
/* These are no-op if |status| is NULL. */
void upb_status_clear(upb_status *status);
void upb_status_seterrmsg(upb_status *status, const char *msg);
void upb_status_seterrf(upb_status *status, const char *fmt, ...);
void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args);
void upb_status_vappenderrf(upb_status *status, const char *fmt, va_list args);
void upb_status_seterrf(upb_status *status, const char *fmt, ...)
UPB_PRINTF(2, 3);
void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args)
UPB_PRINTF(2, 0);
void upb_status_vappenderrf(upb_status *status, const char *fmt, va_list args)
UPB_PRINTF(2, 0);
/** upb_strview ************************************************************/
@ -324,6 +327,10 @@ UPB_INLINE int _upb_lg2ceil(int x) {
#endif
}
UPB_INLINE int _upb_lg2ceilsize(int x) {
return 1 << _upb_lg2ceil(x);
}
#include "upb/port_undef.inc"
#ifdef __cplusplus

@ -6,15 +6,27 @@ load(
licenses(["notice"])
cc_library(
name = "upbc_generator",
name = "common",
hdrs = ["common.h"],
srcs = ["common.cc"],
copts = UPB_DEFAULT_CPPOPTS,
deps = [
"@com_google_protobuf//:protobuf",
"@com_google_absl//absl/strings",
],
)
cc_binary(
name = "protoc-gen-upb",
srcs = [
"generator.cc",
"protoc-gen-upb.cc",
"message_layout.cc",
"message_layout.h",
],
hdrs = ["generator.h"],
copts = UPB_DEFAULT_CPPOPTS,
visibility = ["//visibility:public"],
deps = [
":common",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/strings",
@ -24,12 +36,18 @@ cc_library(
)
cc_binary(
name = "protoc-gen-upb",
srcs = ["main.cc"],
name = "protoc-gen-upbdefs",
srcs = [
"protoc-gen-upbdefs.cc",
],
copts = UPB_DEFAULT_CPPOPTS,
visibility = ["//visibility:public"],
deps = [
":upbc_generator",
":common",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/strings",
"@com_google_protobuf//:protobuf",
"@com_google_protobuf//:protoc_lib",
],
)

@ -0,0 +1,65 @@
#include "absl/strings/str_replace.h"
#include "upbc/common.h"
namespace upbc {
namespace {
namespace protobuf = ::google::protobuf;
void AddMessages(const protobuf::Descriptor* message,
std::vector<const protobuf::Descriptor*>* messages) {
messages->push_back(message);
for (int i = 0; i < message->nested_type_count(); i++) {
AddMessages(message->nested_type(i), messages);
}
}
} // namespace
std::string StripExtension(absl::string_view fname) {
size_t lastdot = fname.find_last_of('.');
if (lastdot == std::string::npos) {
return std::string(fname);
}
return std::string(fname.substr(0, lastdot));
}
std::string ToCIdent(absl::string_view str) {
return absl::StrReplaceAll(str, {{".", "_"}, {"/", "_"}});
}
std::string ToPreproc(absl::string_view str) {
return absl::AsciiStrToUpper(ToCIdent(str));
}
void EmitFileWarning(const protobuf::FileDescriptor* file, Output& output) {
output(
"/* This file was generated by upbc (the upb compiler) from the input\n"
" * file:\n"
" *\n"
" * $0\n"
" *\n"
" * Do not edit -- your changes will be discarded when the file is\n"
" * regenerated. */\n\n",
file->name());
}
std::vector<const protobuf::Descriptor*> SortedMessages(
const protobuf::FileDescriptor* file) {
std::vector<const protobuf::Descriptor*> messages;
for (int i = 0; i < file->message_type_count(); i++) {
AddMessages(file->message_type(i), &messages);
}
return messages;
}
std::string MessageName(const protobuf::Descriptor* descriptor) {
return ToCIdent(descriptor->full_name());
}
std::string MessageInit(const protobuf::Descriptor* descriptor) {
return MessageName(descriptor) + "_msginit";
}
} // namespace upbc

@ -0,0 +1,66 @@
#ifndef UPBC_COMMON_H
#define UPBC_COMMON_H
#include <vector>
#include "absl/strings/substitute.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/io/zero_copy_stream.h"
namespace upbc {
class Output {
public:
Output(google::protobuf::io::ZeroCopyOutputStream* stream)
: stream_(stream) {}
~Output() { stream_->BackUp((int)size_); }
template <class... Arg>
void operator()(absl::string_view format, const Arg&... arg) {
Write(absl::Substitute(format, arg...));
}
private:
void Write(absl::string_view data) {
while (!data.empty()) {
RefreshOutput();
size_t to_write = std::min(data.size(), size_);
memcpy(ptr_, data.data(), to_write);
data.remove_prefix(to_write);
ptr_ += to_write;
size_ -= to_write;
}
}
void RefreshOutput() {
while (size_ == 0) {
void *ptr;
int size;
if (!stream_->Next(&ptr, &size)) {
fprintf(stderr, "upbc: Failed to write to to output\n");
abort();
}
ptr_ = static_cast<char*>(ptr);
size_ = size;
}
}
google::protobuf::io::ZeroCopyOutputStream* stream_;
char *ptr_ = nullptr;
size_t size_ = 0;
};
std::string StripExtension(absl::string_view fname);
std::string ToCIdent(absl::string_view str);
std::string ToPreproc(absl::string_view str);
void EmitFileWarning(const google::protobuf::FileDescriptor* file,
Output& output);
std::vector<const google::protobuf::Descriptor*> SortedMessages(
const google::protobuf::FileDescriptor* file);
std::string MessageInit(const google::protobuf::Descriptor* descriptor);
std::string MessageName(const google::protobuf::Descriptor* descriptor);
} // namespace upbc
# endif // UPBC_COMMON_H

@ -1,12 +0,0 @@
#ifndef UPBC_GENERATOR_H_
#define UPBC_GENERATOR_H_
#include <memory>
#include <google/protobuf/compiler/code_generator.h>
namespace upbc {
std::unique_ptr<google::protobuf::compiler::CodeGenerator> GetGenerator();
}
#endif // UPBC_GENERATOR_H_

@ -1,9 +0,0 @@
#include "google/protobuf/compiler/plugin.h"
#include "upbc/generator.h"
int main(int argc, char** argv) {
return google::protobuf::compiler::PluginMain(argc, argv,
upbc::GetGenerator().get());
}

@ -1,107 +1,31 @@
#include "upbc/generator.h"
#include <memory>
#include "absl/base/attributes.h"
#include "absl/container/flat_hash_map.h"
#include "absl/strings/ascii.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/substitute.h"
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/plugin.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/zero_copy_stream.h"
#include "google/protobuf/wire_format.h"
#include "upbc/common.h"
#include "upbc/message_layout.h"
namespace upbc {
namespace {
namespace protoc = ::google::protobuf::compiler;
namespace protobuf = ::google::protobuf;
static std::string StripExtension(absl::string_view fname) {
size_t lastdot = fname.find_last_of(".");
if (lastdot == std::string::npos) {
return std::string(fname);
}
return std::string(fname.substr(0, lastdot));
}
static std::string HeaderFilename(std::string proto_filename) {
std::string HeaderFilename(std::string proto_filename) {
return StripExtension(proto_filename) + ".upb.h";
}
static std::string SourceFilename(std::string proto_filename) {
std::string SourceFilename(std::string proto_filename) {
return StripExtension(proto_filename) + ".upb.c";
}
static std::string DefHeaderFilename(std::string proto_filename) {
return StripExtension(proto_filename) + ".upbdefs.h";
}
static std::string DefSourceFilename(std::string proto_filename) {
return StripExtension(proto_filename) + ".upbdefs.c";
}
class Output {
public:
Output(protobuf::io::ZeroCopyOutputStream* stream) : stream_(stream) {}
~Output() { stream_->BackUp((int)size_); }
template <class... Arg>
void operator()(absl::string_view format, const Arg&... arg) {
Write(absl::Substitute(format, arg...));
}
private:
void Write(absl::string_view data) {
while (!data.empty()) {
RefreshOutput();
size_t to_write = std::min(data.size(), size_);
memcpy(ptr_, data.data(), to_write);
data.remove_prefix(to_write);
ptr_ += to_write;
size_ -= to_write;
}
}
void RefreshOutput() {
while (size_ == 0) {
void *ptr;
int size;
if (!stream_->Next(&ptr, &size)) {
fprintf(stderr, "upbc: Failed to write to to output\n");
abort();
}
ptr_ = static_cast<char*>(ptr);
size_ = size;
}
}
protobuf::io::ZeroCopyOutputStream* stream_;
char *ptr_ = nullptr;
size_t size_ = 0;
};
namespace upbc {
class Generator : public protoc::CodeGenerator {
~Generator() override {}
bool Generate(const protobuf::FileDescriptor* file,
const std::string& parameter, protoc::GeneratorContext* context,
std::string* error) const override;
uint64_t GetSupportedFeatures() const override {
return FEATURE_PROTO3_OPTIONAL;
}
};
void AddMessages(const protobuf::Descriptor* message,
std::vector<const protobuf::Descriptor*>* messages) {
messages->push_back(message);
for (int i = 0; i < message->nested_type_count(); i++) {
AddMessages(message->nested_type(i), messages);
}
}
void AddEnums(const protobuf::Descriptor* message,
std::vector<const protobuf::EnumDescriptor*>* enums) {
for (int i = 0; i < message->enum_type_count(); i++) {
@ -118,15 +42,6 @@ void SortDefs(std::vector<T>* defs) {
[](T a, T b) { return a->full_name() < b->full_name(); });
}
std::vector<const protobuf::Descriptor*> SortedMessages(
const protobuf::FileDescriptor* file) {
std::vector<const protobuf::Descriptor*> messages;
for (int i = 0; i < file->message_type_count(); i++) {
AddMessages(file->message_type(i), &messages);
}
return messages;
}
std::vector<const protobuf::EnumDescriptor*> SortedEnums(
const protobuf::FileDescriptor* file) {
std::vector<const protobuf::EnumDescriptor*> enums;
@ -172,18 +87,6 @@ std::vector<const protobuf::FieldDescriptor*> SortedSubmessages(
return ret;
}
std::string ToCIdent(absl::string_view str) {
return absl::StrReplaceAll(str, {{".", "_"}, {"/", "_"}});
}
std::string DefInitSymbol(const protobuf::FileDescriptor *file) {
return ToCIdent(file->name()) + "_upbdefinit";
}
std::string ToPreproc(absl::string_view str) {
return absl::AsciiStrToUpper(ToCIdent(str));
}
std::string EnumValueSymbol(const protobuf::EnumValueDescriptor* value) {
return ToCIdent(value->full_name());
}
@ -192,14 +95,6 @@ std::string GetSizeInit(const MessageLayout::Size& size) {
return absl::Substitute("UPB_SIZE($0, $1)", size.size32, size.size64);
}
std::string MessageName(const protobuf::Descriptor* descriptor) {
return ToCIdent(descriptor->full_name());
}
std::string MessageInit(const protobuf::Descriptor* descriptor) {
return MessageName(descriptor) + "_msginit";
}
std::string CTypeInternal(const protobuf::FieldDescriptor* field,
bool is_const) {
std::string maybe_const = is_const ? "const " : "";
@ -320,18 +215,6 @@ void DumpEnumValues(const protobuf::EnumDescriptor* desc, Output& output) {
}
}
void EmitFileWarning(const protobuf::FileDescriptor* file, Output& output) {
output(
"/* This file was generated by upbc (the upb compiler) from the input\n"
" * file:\n"
" *\n"
" * $0\n"
" *\n"
" * Do not edit -- your changes will be discarded when the file is\n"
" * regenerated. */\n\n",
file->name());
}
void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output) {
MessageLayout layout(message);
@ -1064,150 +947,47 @@ void WriteSource(const protobuf::FileDescriptor* file, Output& output,
output("\n");
}
void GenerateMessageDefAccessor(const protobuf::Descriptor* d, Output& output) {
output("UPB_INLINE const upb_msgdef *$0_getmsgdef(upb_symtab *s) {\n",
ToCIdent(d->full_name()));
output(" _upb_symtab_loaddefinit(s, &$0);\n", DefInitSymbol(d->file()));
output(" return upb_symtab_lookupmsg(s, \"$0\");\n", d->full_name());
output("}\n");
output("\n");
for (int i = 0; i < d->nested_type_count(); i++) {
GenerateMessageDefAccessor(d->nested_type(i), output);
}
}
void WriteDefHeader(const protobuf::FileDescriptor* file, Output& output) {
EmitFileWarning(file, output);
output(
"#ifndef $0_UPBDEFS_H_\n"
"#define $0_UPBDEFS_H_\n\n"
"#include \"upb/def.h\"\n"
"#include \"upb/port_def.inc\"\n"
"#ifdef __cplusplus\n"
"extern \"C\" {\n"
"#endif\n\n",
ToPreproc(file->name()));
output("#include \"upb/def.h\"\n");
output("\n");
output("#include \"upb/port_def.inc\"\n");
output("\n");
output("extern upb_def_init $0;\n", DefInitSymbol(file));
output("\n");
for (int i = 0; i < file->message_type_count(); i++) {
GenerateMessageDefAccessor(file->message_type(i), output);
}
output(
"#ifdef __cplusplus\n"
"} /* extern \"C\" */\n"
"#endif\n"
"\n"
"#include \"upb/port_undef.inc\"\n"
"\n"
"#endif /* $0_UPBDEFS_H_ */\n",
ToPreproc(file->name()));
}
// Escape C++ trigraphs by escaping question marks to \?
std::string EscapeTrigraphs(absl::string_view to_escape) {
return absl::StrReplaceAll(to_escape, {{"?", "\\?"}});
}
void WriteDefSource(const protobuf::FileDescriptor* file, Output& output) {
EmitFileWarning(file, output);
output("#include \"upb/def.h\"\n");
output("#include \"$0\"\n", DefHeaderFilename(file->name()));
output("\n");
for (int i = 0; i < file->dependency_count(); i++) {
output("extern upb_def_init $0;\n", DefInitSymbol(file->dependency(i)));
}
std::vector<const protobuf::Descriptor*> file_messages =
SortedMessages(file);
for (auto message : file_messages) {
output("extern const upb_msglayout $0;\n", MessageInit(message));
}
output("\n");
if (!file_messages.empty()) {
output("static const upb_msglayout *layouts[$0] = {\n", file_messages.size());
for (auto message : file_messages) {
output(" &$0,\n", MessageInit(message));
}
output("};\n");
output("\n");
}
protobuf::FileDescriptorProto file_proto;
file->CopyTo(&file_proto);
std::string file_data;
file_proto.SerializeToString(&file_data);
output("static const char descriptor[$0] = {", file_data.size());
// C90 only guarantees that strings can be up to 509 characters, and some
// implementations have limits here (for example, MSVC only allows 64k:
// https://docs.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/fatal-error-c1091.
// So we always emit an array instead of a string.
for (size_t i = 0; i < file_data.size();) {
for (size_t j = 0; j < 25 && i < file_data.size(); ++i, ++j) {
output("'$0', ", absl::CEscape(file_data.substr(i, 1)));
}
output("\n");
}
output("};\n\n");
output("static upb_def_init *deps[$0] = {\n", file->dependency_count() + 1);
for (int i = 0; i < file->dependency_count(); i++) {
output(" &$0,\n", DefInitSymbol(file->dependency(i)));
}
output(" NULL\n");
output("};\n");
output("\n");
output("upb_def_init $0 = {\n", DefInitSymbol(file));
output(" deps,\n");
if (file_messages.empty()) {
output(" NULL,\n");
} else {
output(" layouts,\n");
class Generator : public protoc::CodeGenerator {
~Generator() override {}
bool Generate(const protobuf::FileDescriptor* file,
const std::string& parameter, protoc::GeneratorContext* context,
std::string* error) const override;
uint64_t GetSupportedFeatures() const override {
return FEATURE_PROTO3_OPTIONAL;
}
output(" \"$0\",\n", file->name());
output(" UPB_STRVIEW_INIT(descriptor, $0)\n", file_data.size());
output("};\n");
}
};
bool Generator::Generate(const protobuf::FileDescriptor* file,
const std::string& parameter,
protoc::GeneratorContext* context,
std::string* /* error */) const {
bool fasttable_enabled = parameter == "fasttable";
std::string* error) const {
bool fasttable_enabled = false;
std::vector<std::pair<std::string, std::string>> params;
google::protobuf::compiler::ParseGeneratorParameter(parameter, &params);
for (const auto& pair : params) {
if (pair.first == "fasttable") {
fasttable_enabled = true;
} else {
*error = "Unknown parameter: " + pair.first;
return false;
}
}
Output h_output(context->Open(HeaderFilename(file->name())));
WriteHeader(file, h_output);
Output c_output(context->Open(SourceFilename(file->name())));
WriteSource(file, c_output, fasttable_enabled);
Output h_def_output(context->Open(DefHeaderFilename(file->name())));
WriteDefHeader(file, h_def_output);
Output c_def_output(context->Open(DefSourceFilename(file->name())));
WriteDefSource(file, c_def_output);
return true;
}
std::unique_ptr<google::protobuf::compiler::CodeGenerator> GetGenerator() {
return std::unique_ptr<google::protobuf::compiler::CodeGenerator>(
new Generator());
}
} // namespace
} // namespace upbc
int main(int argc, char** argv) {
std::unique_ptr<google::protobuf::compiler::CodeGenerator> generator(
new upbc::Generator());
return google::protobuf::compiler::PluginMain(argc, argv, generator.get());
}

@ -0,0 +1,183 @@
#include <memory>
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/plugin.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
#include "upbc/common.h"
namespace upbc {
namespace {
namespace protoc = ::google::protobuf::compiler;
namespace protobuf = ::google::protobuf;
std::string DefInitSymbol(const protobuf::FileDescriptor *file) {
return ToCIdent(file->name()) + "_upbdefinit";
}
static std::string DefHeaderFilename(std::string proto_filename) {
return StripExtension(proto_filename) + ".upbdefs.h";
}
static std::string DefSourceFilename(std::string proto_filename) {
return StripExtension(proto_filename) + ".upbdefs.c";
}
void GenerateMessageDefAccessor(const protobuf::Descriptor* d, Output& output) {
output("UPB_INLINE const upb_msgdef *$0_getmsgdef(upb_symtab *s) {\n",
ToCIdent(d->full_name()));
output(" _upb_symtab_loaddefinit(s, &$0);\n", DefInitSymbol(d->file()));
output(" return upb_symtab_lookupmsg(s, \"$0\");\n", d->full_name());
output("}\n");
output("\n");
for (int i = 0; i < d->nested_type_count(); i++) {
GenerateMessageDefAccessor(d->nested_type(i), output);
}
}
void WriteDefHeader(const protobuf::FileDescriptor* file, Output& output) {
EmitFileWarning(file, output);
output(
"#ifndef $0_UPBDEFS_H_\n"
"#define $0_UPBDEFS_H_\n\n"
"#include \"upb/def.h\"\n"
"#include \"upb/port_def.inc\"\n"
"#ifdef __cplusplus\n"
"extern \"C\" {\n"
"#endif\n\n",
ToPreproc(file->name()));
output("#include \"upb/def.h\"\n");
output("\n");
output("#include \"upb/port_def.inc\"\n");
output("\n");
output("extern upb_def_init $0;\n", DefInitSymbol(file));
output("\n");
for (int i = 0; i < file->message_type_count(); i++) {
GenerateMessageDefAccessor(file->message_type(i), output);
}
output(
"#ifdef __cplusplus\n"
"} /* extern \"C\" */\n"
"#endif\n"
"\n"
"#include \"upb/port_undef.inc\"\n"
"\n"
"#endif /* $0_UPBDEFS_H_ */\n",
ToPreproc(file->name()));
}
void WriteDefSource(const protobuf::FileDescriptor* file, Output& output) {
EmitFileWarning(file, output);
output("#include \"upb/def.h\"\n");
output("#include \"$0\"\n", DefHeaderFilename(file->name()));
output("\n");
for (int i = 0; i < file->dependency_count(); i++) {
output("extern upb_def_init $0;\n", DefInitSymbol(file->dependency(i)));
}
std::vector<const protobuf::Descriptor*> file_messages =
SortedMessages(file);
for (auto message : file_messages) {
output("extern const upb_msglayout $0;\n", MessageInit(message));
}
output("\n");
if (!file_messages.empty()) {
output("static const upb_msglayout *layouts[$0] = {\n", file_messages.size());
for (auto message : file_messages) {
output(" &$0,\n", MessageInit(message));
}
output("};\n");
output("\n");
}
protobuf::FileDescriptorProto file_proto;
file->CopyTo(&file_proto);
std::string file_data;
file_proto.SerializeToString(&file_data);
output("static const char descriptor[$0] = {", file_data.size());
// C90 only guarantees that strings can be up to 509 characters, and some
// implementations have limits here (for example, MSVC only allows 64k:
// https://docs.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/fatal-error-c1091.
// So we always emit an array instead of a string.
for (size_t i = 0; i < file_data.size();) {
for (size_t j = 0; j < 25 && i < file_data.size(); ++i, ++j) {
output("'$0', ", absl::CEscape(file_data.substr(i, 1)));
}
output("\n");
}
output("};\n\n");
output("static upb_def_init *deps[$0] = {\n", file->dependency_count() + 1);
for (int i = 0; i < file->dependency_count(); i++) {
output(" &$0,\n", DefInitSymbol(file->dependency(i)));
}
output(" NULL\n");
output("};\n");
output("\n");
output("upb_def_init $0 = {\n", DefInitSymbol(file));
output(" deps,\n");
if (file_messages.empty()) {
output(" NULL,\n");
} else {
output(" layouts,\n");
}
output(" \"$0\",\n", file->name());
output(" UPB_STRVIEW_INIT(descriptor, $0)\n", file_data.size());
output("};\n");
}
class Generator : public protoc::CodeGenerator {
~Generator() override {}
bool Generate(const protobuf::FileDescriptor* file,
const std::string& parameter, protoc::GeneratorContext* context,
std::string* error) const override;
uint64_t GetSupportedFeatures() const override {
return FEATURE_PROTO3_OPTIONAL;
}
};
bool Generator::Generate(const protobuf::FileDescriptor* file,
const std::string& parameter,
protoc::GeneratorContext* context,
std::string* error) const {
std::vector<std::pair<std::string, std::string>> params;
google::protobuf::compiler::ParseGeneratorParameter(parameter, &params);
for (const auto& pair : params) {
*error = "Unknown parameter: " + pair.first;
return false;
}
Output h_def_output(context->Open(DefHeaderFilename(file->name())));
WriteDefHeader(file, h_def_output);
Output c_def_output(context->Open(DefSourceFilename(file->name())));
WriteDefSource(file, c_def_output);
return true;
}
} // namespace
} // namespace upbc
int main(int argc, char** argv) {
std::unique_ptr<google::protobuf::compiler::CodeGenerator> generator(
new upbc::Generator());
return google::protobuf::compiler::PluginMain(argc, argv, generator.get());
}
Loading…
Cancel
Save