diff options
Diffstat (limited to 'upbc/generator.cc')
-rw-r--r-- | upbc/generator.cc | 193 |
1 files changed, 170 insertions, 23 deletions
diff --git a/upbc/generator.cc b/upbc/generator.cc index 0f7d14d..d8ec831 100644 --- a/upbc/generator.cc +++ b/upbc/generator.cc @@ -8,6 +8,7 @@ #include "absl/strings/substitute.h" #include "google/protobuf/compiler/code_generator.h" #include "google/protobuf/descriptor.h" +#include "google/protobuf/descriptor.pb.h" #include "google/protobuf/io/zero_copy_stream.h" #include "upbc/generator.h" @@ -32,6 +33,14 @@ static 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) {} @@ -165,6 +174,10 @@ 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)); } @@ -180,10 +193,6 @@ std::string GetSizeInit(const MessageLayout::Size& size) { std::string CTypeInternal(const protobuf::FieldDescriptor* field, bool is_const) { std::string maybe_const = is_const ? "const " : ""; - if (field->label() == protobuf::FieldDescriptor::LABEL_REPEATED) { - return maybe_const + "upb_array*"; - } - switch (field->cpp_type()) { case protobuf::FieldDescriptor::CPPTYPE_MESSAGE: { std::string maybe_struct = @@ -326,32 +335,74 @@ void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output } for (auto field : FieldNumberOrder(message)) { - output("UPB_INLINE $0 $1_$2(const $1 *msg) {", CTypeConst(field), msgname, - field->name()); - if (field->containing_oneof()) { - output(" return UPB_READ_ONEOF(msg, $0, $1, $2, $3, $4); }\n", - CTypeConst(field), GetSizeInit(layout.GetFieldOffset(field)), - GetSizeInit(layout.GetOneofCaseOffset(field->containing_oneof())), - field->number(), FieldDefault(field)); + + if (layout.HasHasbit(field)) { + output( + "UPB_INLINE bool $0_has_$1(const $0 *msg) { " + "return _upb_has_field(msg, $2); }\n", + msgname, field->name(), layout.GetHasbitIndex(field)); + } else if (field->containing_oneof()) { + output( + "UPB_INLINE bool $0_has_$1(const $0 *msg) { " + "return _upb_has_oneof_field(msg, $2, $3); }\n", + msgname, field->name(), + GetSizeInit(layout.GetOneofCaseOffset(field->containing_oneof())), + field->number()); + } + + if (field->is_repeated()) { + output( + "UPB_INLINE $0 const* $1_$2(const $1 *msg, size_t *len) { " + "return ($0 const*)_upb_array_accessor(msg, $3, len); }\n", + CTypeConst(field), msgname, field->name(), + GetSizeInit(layout.GetFieldOffset(field))); + } else if (field->containing_oneof()) { + output( + "UPB_INLINE $0 $1_$2(const $1 *msg) { " + "return UPB_READ_ONEOF(msg, $0, $3, $4, $5, $6); }\n", + CTypeConst(field), msgname, field->name(), + GetSizeInit(layout.GetFieldOffset(field)), + GetSizeInit(layout.GetOneofCaseOffset(field->containing_oneof())), + field->number(), FieldDefault(field)); } else { - output(" return UPB_FIELD_AT(msg, $0, $1); }\n", CTypeConst(field), - GetSizeInit(layout.GetFieldOffset(field))); + output( + "UPB_INLINE $0 $1_$2(const $1 *msg) { " + "return UPB_FIELD_AT(msg, $0, $3); }\n", + CTypeConst(field), msgname, field->name(), + GetSizeInit(layout.GetFieldOffset(field))); } } output("\n"); for (auto field : FieldNumberOrder(message)) { - output("UPB_INLINE void $0_set_$1($0 *msg, $2 value) { ", msgname, - field->name(), CType(field)); - if (field->containing_oneof()) { - output("UPB_WRITE_ONEOF(msg, $0, $1, value, $2, $3); }\n", CType(field), - GetSizeInit(layout.GetFieldOffset(field)), - GetSizeInit(layout.GetOneofCaseOffset(field->containing_oneof())), - field->number()); + if (field->is_repeated()) { + output( + "UPB_INLINE $0* $1_$2_mutable($1 *msg, size_t *len) { " + "return ($0*)_upb_array_mutable_accessor(msg, $3, len); }\n", + CType(field), msgname, field->name(), + GetSizeInit(layout.GetFieldOffset(field))); + output( + "UPB_INLINE $0* $1_$2_resize($1 *msg, size_t len, " + "upb_arena *arena) { " + "return ($0*)_upb_array_resize_accessor(msg, $3, len, $4, $5, arena); " + "}\n", + CType(field), msgname, field->name(), + GetSizeInit(layout.GetFieldOffset(field)), + GetSizeInit(MessageLayout::SizeOfUnwrapped(field).size), + "(upb_fieldtype_t)0" /* TODO */); } else { - output("UPB_FIELD_AT(msg, $0, $1) = value; }\n", CType(field), - GetSizeInit(layout.GetFieldOffset(field))); + output("UPB_INLINE void $0_set_$1($0 *msg, $2 value) { ", msgname, + field->name(), CType(field)); + if (field->containing_oneof()) { + output("UPB_WRITE_ONEOF(msg, $0, $1, value, $2, $3); }\n", CType(field), + GetSizeInit(layout.GetFieldOffset(field)), + GetSizeInit(layout.GetOneofCaseOffset(field->containing_oneof())), + field->number()); + } else { + output("UPB_FIELD_AT(msg, $0, $1) = value; }\n", CType(field), + GetSizeInit(layout.GetFieldOffset(field))); + } } } @@ -363,6 +414,7 @@ void WriteHeader(const protobuf::FileDescriptor* file, Output& output) { output( "#ifndef $0_UPB_H_\n" "#define $0_UPB_H_\n\n" + "#include \"upb/generated_util.h\"\n\n" "#include \"upb/msg.h\"\n\n" "#include \"upb/decode.h\"\n" "#include \"upb/encode.h\"\n" @@ -482,7 +534,7 @@ void WriteSource(const protobuf::FileDescriptor* file, Output& output) { } if (MessageLayout::HasHasbit(field)) { - presence = absl::StrCat(layout.GetHasbitIndex(field) + 1); + presence = absl::StrCat(layout.GetHasbitIndex(field)); } else if (field->containing_oneof()) { MessageLayout::Size case_offset = layout.GetOneofCaseOffset(field->containing_oneof()); @@ -519,6 +571,95 @@ 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("#include \"upb/def.h\"\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); + } +} + +// 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("\n"); + + for (int i = 0; i < file->dependency_count(); i++) { + output("extern upb_def_init $0;\n", DefInitSymbol(file->dependency(i))); + } + + protobuf::FileDescriptorProto file_proto; + file->CopyTo(&file_proto); + std::string file_data; + file_proto.SerializeToString(&file_data); + + output("static const char descriptor[$0] =\n", file_data.size()); + + { + if (file_data.size() > 65535) { + // Workaround for MSVC: "Error C1091: compiler limit: string exceeds + // 65535 bytes in length". Declare a static array of chars rather than + // use a string literal. Only write 25 bytes per line. + static const size_t kBytesPerLine = 25; + output("{ "); + for (size_t i = 0; i < file_data.size();) { + for (size_t j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) { + output("'$0', ", absl::CEscape(file_data.substr(i, 1))); + } + output("\n"); + } + output("'\\0' }"); // null-terminate + } else { + // Only write 40 bytes per line. + static const size_t kBytesPerLine = 40; + for (size_t i = 0; i < file_data.size(); i += kBytesPerLine) { + output( + "\"$0\"\n", + EscapeTrigraphs(absl::CEscape(file_data.substr(i, kBytesPerLine)))); + } + } + output(";\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("upb_def_init $0 = {\n", DefInitSymbol(file)); + output(" deps,\n"); + output(" \"$0\",\n", file->name()); + output(" UPB_STRINGVIEW_INIT(descriptor, $0)\n", file_data.size()); + output("};\n"); +} + bool Generator::Generate(const protobuf::FileDescriptor* file, const std::string& parameter, protoc::GeneratorContext* context, @@ -529,6 +670,12 @@ bool Generator::Generate(const protobuf::FileDescriptor* file, Output c_output(context->Open(SourceFilename(file->name()))); WriteSource(file, c_output); + 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; } |