parent
125db89ff5
commit
46e306bead
12 changed files with 880 additions and 520 deletions
@ -0,0 +1,383 @@ |
|||||||
|
// Copyright (c) 2009-2021, Google LLC
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of Google LLC nor the
|
||||||
|
// names of its contributors may be used to endorse or promote products
|
||||||
|
// derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
|
||||||
|
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include "upbc/file_layout.h" |
||||||
|
|
||||||
|
#include <string> |
||||||
|
#include <unordered_set> |
||||||
|
|
||||||
|
#include "upb/mini_table.hpp" |
||||||
|
#include "upbc/common.h" |
||||||
|
|
||||||
|
namespace upbc { |
||||||
|
|
||||||
|
namespace protobuf = ::google::protobuf; |
||||||
|
|
||||||
|
const char* kEnumsInit = "enums_layout"; |
||||||
|
const char* kExtensionsInit = "extensions_layout"; |
||||||
|
const char* kMessagesInit = "messages_layout"; |
||||||
|
|
||||||
|
void AddEnums(const protobuf::Descriptor* message, |
||||||
|
std::vector<const protobuf::EnumDescriptor*>* enums) { |
||||||
|
enums->reserve(enums->size() + message->enum_type_count()); |
||||||
|
for (int i = 0; i < message->enum_type_count(); i++) { |
||||||
|
enums->push_back(message->enum_type(i)); |
||||||
|
} |
||||||
|
for (int i = 0; i < message->nested_type_count(); i++) { |
||||||
|
AddEnums(message->nested_type(i), enums); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
std::vector<const protobuf::EnumDescriptor*> SortedEnums( |
||||||
|
const protobuf::FileDescriptor* file) { |
||||||
|
std::vector<const protobuf::EnumDescriptor*> enums; |
||||||
|
enums.reserve(file->enum_type_count()); |
||||||
|
for (int i = 0; i < file->enum_type_count(); i++) { |
||||||
|
enums.push_back(file->enum_type(i)); |
||||||
|
} |
||||||
|
for (int i = 0; i < file->message_type_count(); i++) { |
||||||
|
AddEnums(file->message_type(i), &enums); |
||||||
|
} |
||||||
|
return enums; |
||||||
|
} |
||||||
|
|
||||||
|
std::vector<uint32_t> SortedUniqueEnumNumbers( |
||||||
|
const protobuf::EnumDescriptor* e) { |
||||||
|
std::vector<uint32_t> values; |
||||||
|
values.reserve(e->value_count()); |
||||||
|
for (int i = 0; i < e->value_count(); i++) { |
||||||
|
values.push_back(static_cast<uint32_t>(e->value(i)->number())); |
||||||
|
} |
||||||
|
std::sort(values.begin(), values.end()); |
||||||
|
auto last = std::unique(values.begin(), values.end()); |
||||||
|
values.erase(last, values.end()); |
||||||
|
return values; |
||||||
|
} |
||||||
|
|
||||||
|
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); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Ordering must match upb/def.c!
|
||||||
|
//
|
||||||
|
// The ordering is significant because each upb_MessageDef* will point at the
|
||||||
|
// corresponding upb_MiniTable and we just iterate through the list without
|
||||||
|
// any search or lookup.
|
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
void AddExtensionsFromMessage( |
||||||
|
const protobuf::Descriptor* message, |
||||||
|
std::vector<const protobuf::FieldDescriptor*>* exts) { |
||||||
|
for (int i = 0; i < message->extension_count(); i++) { |
||||||
|
exts->push_back(message->extension(i)); |
||||||
|
} |
||||||
|
for (int i = 0; i < message->nested_type_count(); i++) { |
||||||
|
AddExtensionsFromMessage(message->nested_type(i), exts); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Ordering must match upb/def.c!
|
||||||
|
//
|
||||||
|
// The ordering is significant because each upb_FieldDef* will point at the
|
||||||
|
// corresponding upb_MiniTable_Extension and we just iterate through the list
|
||||||
|
// without any search or lookup.
|
||||||
|
std::vector<const protobuf::FieldDescriptor*> SortedExtensions( |
||||||
|
const protobuf::FileDescriptor* file) { |
||||||
|
std::vector<const protobuf::FieldDescriptor*> ret; |
||||||
|
for (int i = 0; i < file->extension_count(); i++) { |
||||||
|
ret.push_back(file->extension(i)); |
||||||
|
} |
||||||
|
for (int i = 0; i < file->message_type_count(); i++) { |
||||||
|
AddExtensionsFromMessage(file->message_type(i), &ret); |
||||||
|
} |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
std::vector<const protobuf::FieldDescriptor*> FieldNumberOrder( |
||||||
|
const protobuf::Descriptor* message) { |
||||||
|
std::vector<const protobuf::FieldDescriptor*> fields; |
||||||
|
for (int i = 0; i < message->field_count(); i++) { |
||||||
|
fields.push_back(message->field(i)); |
||||||
|
} |
||||||
|
std::sort(fields.begin(), fields.end(), |
||||||
|
[](const protobuf::FieldDescriptor* a, |
||||||
|
const protobuf::FieldDescriptor* b) { |
||||||
|
return a->number() < b->number(); |
||||||
|
}); |
||||||
|
return fields; |
||||||
|
} |
||||||
|
|
||||||
|
upb_MiniTable* FilePlatformLayout::GetMiniTable( |
||||||
|
const protobuf::Descriptor* m) const { |
||||||
|
auto it = table_map_.find(m); |
||||||
|
assert(it != table_map_.end()); |
||||||
|
return it->second; |
||||||
|
} |
||||||
|
|
||||||
|
upb_MiniTable_Enum* FilePlatformLayout::GetEnumTable( |
||||||
|
const protobuf::EnumDescriptor* d) const { |
||||||
|
auto it = enum_map_.find(d); |
||||||
|
assert(it != enum_map_.end()); |
||||||
|
return it->second; |
||||||
|
} |
||||||
|
|
||||||
|
const upb_MiniTable_Extension* FilePlatformLayout::GetExtension( |
||||||
|
const protobuf::FieldDescriptor* fd) const { |
||||||
|
auto it = extension_map_.find(fd); |
||||||
|
assert(it != extension_map_.end()); |
||||||
|
return &it->second; |
||||||
|
} |
||||||
|
|
||||||
|
void FilePlatformLayout::ResolveIntraFileReferences() { |
||||||
|
// This properly resolves references within a file, in order to set any
|
||||||
|
// necessary flags (eg. is a map).
|
||||||
|
for (const auto& pair : table_map_) { |
||||||
|
upb_MiniTable* mt = pair.second; |
||||||
|
// First we properly resolve for defs within the file.
|
||||||
|
for (const auto* f : FieldNumberOrder(pair.first)) { |
||||||
|
if (f->message_type() && f->message_type()->file() == f->file()) { |
||||||
|
// const_cast is safe because the mini-table is owned exclusively
|
||||||
|
// by us, and was allocated from an arena (known-writable memory).
|
||||||
|
upb_MiniTable_Field* mt_f = const_cast<upb_MiniTable_Field*>( |
||||||
|
upb_MiniTable_FindFieldByNumber(mt, f->number())); |
||||||
|
upb_MiniTable* sub_mt = GetMiniTable(f->message_type()); |
||||||
|
upb_MiniTable_SetSubMessage(mt, mt_f, sub_mt); |
||||||
|
} |
||||||
|
// We don't worry about enums here, because resolving an enum will
|
||||||
|
// never alter the mini-table.
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
upb_MiniTable_Sub FilePlatformLayout::PackSub(const char* data, SubTag tag) { |
||||||
|
uintptr_t val = reinterpret_cast<uintptr_t>(data); |
||||||
|
assert((val & kMask) == 0); |
||||||
|
upb_MiniTable_Sub sub; |
||||||
|
sub.submsg = reinterpret_cast<upb_MiniTable*>(val | tag); |
||||||
|
return sub; |
||||||
|
} |
||||||
|
|
||||||
|
bool FilePlatformLayout::IsNull(upb_MiniTable_Sub sub) { |
||||||
|
return reinterpret_cast<uintptr_t>(sub.subenum) == 0; |
||||||
|
} |
||||||
|
|
||||||
|
std::string FilePlatformLayout::GetSub(upb_MiniTable_Sub sub) { |
||||||
|
uintptr_t as_int = reinterpret_cast<uintptr_t>(sub.submsg); |
||||||
|
const char* str = reinterpret_cast<const char*>(as_int & ~SubTag::kMask); |
||||||
|
switch (as_int & SubTag::kMask) { |
||||||
|
case SubTag::kMessage: |
||||||
|
return absl::Substitute("{.submsg = &$0}", str); |
||||||
|
case SubTag::kEnum: |
||||||
|
return absl::Substitute("{.subenum = &$0}", str); |
||||||
|
default: |
||||||
|
return std::string("{.submsg = NULL}"); |
||||||
|
} |
||||||
|
return std::string("ERROR in GetSub"); |
||||||
|
} |
||||||
|
|
||||||
|
void FilePlatformLayout::SetSubTableStrings() { |
||||||
|
for (const auto& pair : table_map_) { |
||||||
|
upb_MiniTable* mt = pair.second; |
||||||
|
for (const auto* f : FieldNumberOrder(pair.first)) { |
||||||
|
upb_MiniTable_Field* mt_f = const_cast<upb_MiniTable_Field*>( |
||||||
|
upb_MiniTable_FindFieldByNumber(mt, f->number())); |
||||||
|
assert(mt_f); |
||||||
|
upb_MiniTable_Sub sub = PackSubForField(f, mt_f); |
||||||
|
if (IsNull(sub)) continue; |
||||||
|
// const_cast is safe because the mini-table is owned exclusively
|
||||||
|
// by us, and was allocated from an arena (known-writable memory).
|
||||||
|
*const_cast<upb_MiniTable_Sub*>(&mt->subs[mt_f->submsg_index]) = sub; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
upb_MiniTable_Sub FilePlatformLayout::PackSubForField( |
||||||
|
const protobuf::FieldDescriptor* f, const upb_MiniTable_Field* mt_f) { |
||||||
|
if (mt_f->submsg_index == kUpb_NoSub) { |
||||||
|
return PackSub(nullptr, SubTag::kNull); |
||||||
|
} else if (f->message_type()) { |
||||||
|
return PackSub(AllocStr(MessageInit(f->message_type())), SubTag::kMessage); |
||||||
|
} else { |
||||||
|
ABSL_ASSERT(f->enum_type()); |
||||||
|
return PackSub(AllocStr(EnumInit(f->enum_type())), SubTag::kEnum); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const char* FilePlatformLayout::AllocStr(absl::string_view str) { |
||||||
|
char* ret = |
||||||
|
static_cast<char*>(upb_Arena_Malloc(arena_.ptr(), str.size() + 1)); |
||||||
|
memcpy(ret, str.data(), str.size()); |
||||||
|
ret[str.size()] = '\0'; |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
void FilePlatformLayout::BuildMiniTables(const protobuf::FileDescriptor* fd) { |
||||||
|
for (const auto& m : SortedMessages(fd)) { |
||||||
|
table_map_[m] = MakeMiniTable(m); |
||||||
|
} |
||||||
|
for (const auto& e : SortedEnums(fd)) { |
||||||
|
enum_map_[e] = MakeMiniTableEnum(e); |
||||||
|
} |
||||||
|
ResolveIntraFileReferences(); |
||||||
|
SetSubTableStrings(); |
||||||
|
} |
||||||
|
|
||||||
|
void FilePlatformLayout::BuildExtensions(const protobuf::FileDescriptor* fd) { |
||||||
|
std::vector<const protobuf::FieldDescriptor*> sorted = SortedExtensions(fd); |
||||||
|
upb::Status status; |
||||||
|
for (const auto* f : sorted) { |
||||||
|
upb::MtDataEncoder e; |
||||||
|
e.StartMessage(0); |
||||||
|
e.PutField(static_cast<upb_FieldType>(f->type()), f->number(), |
||||||
|
GetFieldModifiers(f)); |
||||||
|
upb_MiniTable_Extension& ext = extension_map_[f]; |
||||||
|
upb_MiniTable_Sub sub; |
||||||
|
bool ok = upb_MiniTable_BuildExtension(e.data().data(), e.data().size(), |
||||||
|
&ext, sub, status.ptr()); |
||||||
|
if (!ok) { |
||||||
|
// TODO(haberman): Use ABSL CHECK() when it is available.
|
||||||
|
fprintf(stderr, "Error building mini-table: %s\n", |
||||||
|
status.error_message()); |
||||||
|
} |
||||||
|
ABSL_ASSERT(ok); |
||||||
|
ext.extendee = reinterpret_cast<const upb_MiniTable*>( |
||||||
|
AllocStr(MessageInit(f->containing_type()))); |
||||||
|
ext.sub = PackSubForField(f, &ext.field); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
upb_MiniTable* FilePlatformLayout::MakeMiniTable( |
||||||
|
const protobuf::Descriptor* m) { |
||||||
|
if (m->options().message_set_wire_format()) { |
||||||
|
return upb_MiniTable_BuildMessageSet(platform_, arena_.ptr()); |
||||||
|
} else if (m->options().map_entry()) { |
||||||
|
return upb_MiniTable_BuildMapEntry( |
||||||
|
static_cast<upb_FieldType>(m->map_key()->type()), |
||||||
|
static_cast<upb_FieldType>(m->map_value()->type()), |
||||||
|
m->map_value()->enum_type() && |
||||||
|
m->map_value()->enum_type()->file()->syntax() == |
||||||
|
protobuf::FileDescriptor::SYNTAX_PROTO3, |
||||||
|
platform_, arena_.ptr()); |
||||||
|
} else { |
||||||
|
return MakeRegularMiniTable(m); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
upb_MiniTable* FilePlatformLayout::MakeRegularMiniTable( |
||||||
|
const protobuf::Descriptor* m) { |
||||||
|
upb::MtDataEncoder e; |
||||||
|
e.StartMessage(GetMessageModifiers(m)); |
||||||
|
for (const auto* f : FieldNumberOrder(m)) { |
||||||
|
e.PutField(static_cast<upb_FieldType>(f->type()), f->number(), |
||||||
|
GetFieldModifiers(f)); |
||||||
|
} |
||||||
|
for (int i = 0; i < m->real_oneof_decl_count(); i++) { |
||||||
|
const protobuf::OneofDescriptor* oneof = m->oneof_decl(i); |
||||||
|
e.StartOneof(); |
||||||
|
for (int j = 0; j < oneof->field_count(); j++) { |
||||||
|
const protobuf::FieldDescriptor* f = oneof->field(j); |
||||||
|
e.PutOneofField(f->number()); |
||||||
|
} |
||||||
|
} |
||||||
|
absl::string_view str = e.data(); |
||||||
|
upb::Status status; |
||||||
|
upb_MiniTable* ret = upb_MiniTable_Build(str.data(), str.size(), platform_, |
||||||
|
arena_.ptr(), status.ptr()); |
||||||
|
if (!ret) { |
||||||
|
fprintf(stderr, "Error building mini-table: %s\n", status.error_message()); |
||||||
|
} |
||||||
|
assert(ret); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
upb_MiniTable_Enum* FilePlatformLayout::MakeMiniTableEnum( |
||||||
|
const protobuf::EnumDescriptor* d) { |
||||||
|
upb::Arena arena; |
||||||
|
upb::MtDataEncoder e; |
||||||
|
|
||||||
|
e.StartEnum(); |
||||||
|
for (uint32_t i : SortedUniqueEnumNumbers(d)) { |
||||||
|
e.PutEnumValue(i); |
||||||
|
} |
||||||
|
e.EndEnum(); |
||||||
|
|
||||||
|
absl::string_view str = e.data(); |
||||||
|
upb::Status status; |
||||||
|
upb_MiniTable_Enum* ret = upb_MiniTable_BuildEnum(str.data(), str.size(), |
||||||
|
arena_.ptr(), status.ptr()); |
||||||
|
if (!ret) { |
||||||
|
fprintf(stderr, "Error building mini-table: %s\n", status.error_message()); |
||||||
|
} |
||||||
|
assert(ret); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
uint64_t FilePlatformLayout::GetMessageModifiers( |
||||||
|
const protobuf::Descriptor* m) { |
||||||
|
uint64_t ret = 0; |
||||||
|
|
||||||
|
if (m->file()->syntax() == protobuf::FileDescriptor::SYNTAX_PROTO3) { |
||||||
|
ret |= kUpb_MessageModifier_ValidateUtf8; |
||||||
|
ret |= kUpb_MessageModifier_DefaultIsPacked; |
||||||
|
} |
||||||
|
|
||||||
|
if (m->extension_range_count() > 0) { |
||||||
|
ret |= kUpb_MessageModifier_IsExtendable; |
||||||
|
} |
||||||
|
|
||||||
|
assert(!m->options().map_entry()); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
uint64_t FilePlatformLayout::GetFieldModifiers( |
||||||
|
const protobuf::FieldDescriptor* f) { |
||||||
|
uint64_t ret = 0; |
||||||
|
|
||||||
|
if (f->is_repeated()) ret |= kUpb_FieldModifier_IsRepeated; |
||||||
|
if (f->is_required()) ret |= kUpb_FieldModifier_IsRequired; |
||||||
|
if (f->is_packed()) ret |= kUpb_FieldModifier_IsPacked; |
||||||
|
if (f->enum_type() && f->enum_type()->file()->syntax() == |
||||||
|
protobuf::FileDescriptor::SYNTAX_PROTO2) { |
||||||
|
ret |= kUpb_FieldModifier_IsClosedEnum; |
||||||
|
} |
||||||
|
if (f->is_optional() && !f->has_presence()) { |
||||||
|
ret |= kUpb_FieldModifier_IsProto3Singular; |
||||||
|
} |
||||||
|
|
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace upbc
|
@ -0,0 +1,211 @@ |
|||||||
|
// Copyright (c) 2009-2021, Google LLC
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of Google LLC nor the
|
||||||
|
// names of its contributors may be used to endorse or promote products
|
||||||
|
// derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
|
||||||
|
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#ifndef UPBC_FILE_LAYOUT_H |
||||||
|
#define UPBC_FILE_LAYOUT_H |
||||||
|
|
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include "google/protobuf/descriptor.pb.h" |
||||||
|
#include "absl/container/flat_hash_map.h" |
||||||
|
#include "absl/strings/substitute.h" |
||||||
|
#include "upb/mini_table.hpp" |
||||||
|
#include "upb/upb.hpp" |
||||||
|
|
||||||
|
namespace upbc { |
||||||
|
|
||||||
|
namespace protoc = ::google::protobuf::compiler; |
||||||
|
namespace protobuf = ::google::protobuf; |
||||||
|
|
||||||
|
std::vector<const protobuf::EnumDescriptor*> SortedEnums( |
||||||
|
const protobuf::FileDescriptor* file); |
||||||
|
|
||||||
|
// Ordering must match upb/def.c!
|
||||||
|
//
|
||||||
|
// The ordering is significant because each upb_MessageDef* will point at the
|
||||||
|
// corresponding upb_MiniTable and we just iterate through the list without
|
||||||
|
// any search or lookup.
|
||||||
|
std::vector<const protobuf::Descriptor*> SortedMessages( |
||||||
|
const protobuf::FileDescriptor* file); |
||||||
|
|
||||||
|
// Ordering must match upb/def.c!
|
||||||
|
//
|
||||||
|
// The ordering is significant because each upb_FieldDef* will point at the
|
||||||
|
// corresponding upb_MiniTable_Extension and we just iterate through the list
|
||||||
|
// without any search or lookup.
|
||||||
|
std::vector<const protobuf::FieldDescriptor*> SortedExtensions( |
||||||
|
const protobuf::FileDescriptor* file); |
||||||
|
|
||||||
|
std::vector<const protobuf::FieldDescriptor*> FieldNumberOrder( |
||||||
|
const protobuf::Descriptor* message); |
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// FilePlatformLayout
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// FilePlatformLayout builds and vends upb MiniTables for a given platform (32
|
||||||
|
// or 64 bit).
|
||||||
|
class FilePlatformLayout { |
||||||
|
public: |
||||||
|
FilePlatformLayout(const protobuf::FileDescriptor* fd, |
||||||
|
upb_MiniTablePlatform platform) |
||||||
|
: platform_(platform) { |
||||||
|
BuildMiniTables(fd); |
||||||
|
BuildExtensions(fd); |
||||||
|
} |
||||||
|
|
||||||
|
// Retrieves a upb MiniTable or Extension given a protobuf descriptor. The
|
||||||
|
// descriptor must be from this layout's file.
|
||||||
|
upb_MiniTable* GetMiniTable(const protobuf::Descriptor* m) const; |
||||||
|
upb_MiniTable_Enum* GetEnumTable(const protobuf::EnumDescriptor* d) const; |
||||||
|
const upb_MiniTable_Extension* GetExtension( |
||||||
|
const protobuf::FieldDescriptor* fd) const; |
||||||
|
|
||||||
|
// Get the initializer for the given sub-message/sub-enum link.
|
||||||
|
static std::string GetSub(upb_MiniTable_Sub sub); |
||||||
|
|
||||||
|
private: |
||||||
|
// Functions to build mini-tables for this file's messages and extensions.
|
||||||
|
void BuildMiniTables(const protobuf::FileDescriptor* fd); |
||||||
|
void BuildExtensions(const protobuf::FileDescriptor* fd); |
||||||
|
upb_MiniTable* MakeMiniTable(const protobuf::Descriptor* m); |
||||||
|
upb_MiniTable* MakeRegularMiniTable(const protobuf::Descriptor* m); |
||||||
|
upb_MiniTable_Enum* MakeMiniTableEnum(const protobuf::EnumDescriptor* d); |
||||||
|
uint64_t GetMessageModifiers(const protobuf::Descriptor* m); |
||||||
|
uint64_t GetFieldModifiers(const protobuf::FieldDescriptor* f); |
||||||
|
void ResolveIntraFileReferences(); |
||||||
|
|
||||||
|
// When we are generating code, tables are linked to sub-tables via name (ie.
|
||||||
|
// a string) rather than by pointer. We need to emit an initializer like
|
||||||
|
// `&foo_sub_table`. To do this, we store `const char*` strings in all the
|
||||||
|
// links that would normally be pointers:
|
||||||
|
// field -> sub-message
|
||||||
|
// field -> enum table (proto2 only)
|
||||||
|
// extension -> extendee
|
||||||
|
//
|
||||||
|
// This requires a bit of reinterpret_cast<>(), but it's confined to a few
|
||||||
|
// functions. We tag the pointer so we know which member of the union to
|
||||||
|
// initialize.
|
||||||
|
enum SubTag { |
||||||
|
kNull = 0, |
||||||
|
kMessage = 1, |
||||||
|
kEnum = 2, |
||||||
|
kMask = 3, |
||||||
|
}; |
||||||
|
|
||||||
|
static upb_MiniTable_Sub PackSub(const char* data, SubTag tag); |
||||||
|
static bool IsNull(upb_MiniTable_Sub sub); |
||||||
|
void SetSubTableStrings(); |
||||||
|
upb_MiniTable_Sub PackSubForField(const protobuf::FieldDescriptor* f, |
||||||
|
const upb_MiniTable_Field* mt_f); |
||||||
|
const char* AllocStr(absl::string_view str); |
||||||
|
|
||||||
|
private: |
||||||
|
using TableMap = |
||||||
|
absl::flat_hash_map<const protobuf::Descriptor*, upb_MiniTable*>; |
||||||
|
using EnumMap = |
||||||
|
absl::flat_hash_map<const protobuf::EnumDescriptor*, upb_MiniTable_Enum*>; |
||||||
|
using ExtensionMap = absl::flat_hash_map<const protobuf::FieldDescriptor*, |
||||||
|
upb_MiniTable_Extension>; |
||||||
|
upb::Arena arena_; |
||||||
|
TableMap table_map_; |
||||||
|
EnumMap enum_map_; |
||||||
|
ExtensionMap extension_map_; |
||||||
|
upb_MiniTablePlatform platform_; |
||||||
|
}; |
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// FileLayout
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// FileLayout is a pair of platform layouts: one for 32-bit and one for 64-bit.
|
||||||
|
class FileLayout { |
||||||
|
public: |
||||||
|
FileLayout(const protobuf::FileDescriptor* fd) |
||||||
|
: descriptor_(fd), |
||||||
|
layout32_(fd, kUpb_MiniTablePlatform_32Bit), |
||||||
|
layout64_(fd, kUpb_MiniTablePlatform_64Bit) {} |
||||||
|
|
||||||
|
const protobuf::FileDescriptor* descriptor() const { return descriptor_; } |
||||||
|
|
||||||
|
const upb_MiniTable* GetMiniTable32(const protobuf::Descriptor* m) const { |
||||||
|
return layout32_.GetMiniTable(m); |
||||||
|
} |
||||||
|
|
||||||
|
const upb_MiniTable* GetMiniTable64(const protobuf::Descriptor* m) const { |
||||||
|
return layout64_.GetMiniTable(m); |
||||||
|
} |
||||||
|
|
||||||
|
const upb_MiniTable_Enum* GetEnumTable( |
||||||
|
const protobuf::EnumDescriptor* d) const { |
||||||
|
return layout64_.GetEnumTable(d); |
||||||
|
} |
||||||
|
|
||||||
|
std::string GetFieldOffset(const protobuf::FieldDescriptor* f) const { |
||||||
|
const upb_MiniTable_Field* f_32 = upb_MiniTable_FindFieldByNumber( |
||||||
|
GetMiniTable32(f->containing_type()), f->number()); |
||||||
|
const upb_MiniTable_Field* f_64 = upb_MiniTable_FindFieldByNumber( |
||||||
|
GetMiniTable64(f->containing_type()), f->number()); |
||||||
|
return absl::Substitute("UPB_SIZE($0, $1)", f_32->offset, f_64->offset); |
||||||
|
} |
||||||
|
|
||||||
|
std::string GetOneofCaseOffset(const protobuf::OneofDescriptor* o) const { |
||||||
|
const protobuf::FieldDescriptor* f = o->field(0); |
||||||
|
const upb_MiniTable_Field* f_32 = upb_MiniTable_FindFieldByNumber( |
||||||
|
GetMiniTable32(f->containing_type()), f->number()); |
||||||
|
const upb_MiniTable_Field* f_64 = upb_MiniTable_FindFieldByNumber( |
||||||
|
GetMiniTable64(f->containing_type()), f->number()); |
||||||
|
return absl::Substitute("UPB_SIZE($0, $1)", ~f_32->presence, |
||||||
|
~f_64->presence); |
||||||
|
} |
||||||
|
|
||||||
|
std::string GetMessageSize(const protobuf::Descriptor* d) const { |
||||||
|
return absl::Substitute("UPB_SIZE($0, $1)", GetMiniTable32(d)->size, |
||||||
|
GetMiniTable64(d)->size); |
||||||
|
} |
||||||
|
|
||||||
|
int GetHasbitIndex(const protobuf::FieldDescriptor* f) const { |
||||||
|
const upb_MiniTable_Field* f_64 = upb_MiniTable_FindFieldByNumber( |
||||||
|
GetMiniTable64(f->containing_type()), f->number()); |
||||||
|
return f_64->presence; |
||||||
|
} |
||||||
|
|
||||||
|
bool HasHasbit(const protobuf::FieldDescriptor* f) const { |
||||||
|
return GetHasbitIndex(f) > 0; |
||||||
|
} |
||||||
|
|
||||||
|
const upb_MiniTable_Extension* GetExtension( |
||||||
|
const protobuf::FieldDescriptor* f) const { |
||||||
|
return layout64_.GetExtension(f); |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
const protobuf::FileDescriptor* descriptor_; |
||||||
|
FilePlatformLayout layout32_; |
||||||
|
FilePlatformLayout layout64_; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace upbc
|
||||||
|
|
||||||
|
#endif // UPBC_FILE_LAYOUT_H
|
@ -0,0 +1,151 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2007-2021, Google LLC |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* * Neither the name of Google LLC nor the |
||||||
|
* names of its contributors may be used to endorse or promote products |
||||||
|
* derived from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "upbc/keywords.h" |
||||||
|
|
||||||
|
#include <string> |
||||||
|
#include <unordered_set> |
||||||
|
|
||||||
|
namespace upbc { |
||||||
|
|
||||||
|
static const char* const kKeywordList[] = { |
||||||
|
//
|
||||||
|
"NULL", |
||||||
|
"alignas", |
||||||
|
"alignof", |
||||||
|
"and", |
||||||
|
"and_eq", |
||||||
|
"asm", |
||||||
|
"auto", |
||||||
|
"bitand", |
||||||
|
"bitor", |
||||||
|
"bool", |
||||||
|
"break", |
||||||
|
"case", |
||||||
|
"catch", |
||||||
|
"char", |
||||||
|
"class", |
||||||
|
"compl", |
||||||
|
"const", |
||||||
|
"constexpr", |
||||||
|
"const_cast", |
||||||
|
"continue", |
||||||
|
"decltype", |
||||||
|
"default", |
||||||
|
"delete", |
||||||
|
"do", |
||||||
|
"double", |
||||||
|
"dynamic_cast", |
||||||
|
"else", |
||||||
|
"enum", |
||||||
|
"explicit", |
||||||
|
"export", |
||||||
|
"extern", |
||||||
|
"false", |
||||||
|
"float", |
||||||
|
"for", |
||||||
|
"friend", |
||||||
|
"goto", |
||||||
|
"if", |
||||||
|
"inline", |
||||||
|
"int", |
||||||
|
"long", |
||||||
|
"mutable", |
||||||
|
"namespace", |
||||||
|
"new", |
||||||
|
"noexcept", |
||||||
|
"not", |
||||||
|
"not_eq", |
||||||
|
"nullptr", |
||||||
|
"operator", |
||||||
|
"or", |
||||||
|
"or_eq", |
||||||
|
"private", |
||||||
|
"protected", |
||||||
|
"public", |
||||||
|
"register", |
||||||
|
"reinterpret_cast", |
||||||
|
"return", |
||||||
|
"short", |
||||||
|
"signed", |
||||||
|
"sizeof", |
||||||
|
"static", |
||||||
|
"static_assert", |
||||||
|
"static_cast", |
||||||
|
"struct", |
||||||
|
"switch", |
||||||
|
"template", |
||||||
|
"this", |
||||||
|
"thread_local", |
||||||
|
"throw", |
||||||
|
"true", |
||||||
|
"try", |
||||||
|
"typedef", |
||||||
|
"typeid", |
||||||
|
"typename", |
||||||
|
"union", |
||||||
|
"unsigned", |
||||||
|
"using", |
||||||
|
"virtual", |
||||||
|
"void", |
||||||
|
"volatile", |
||||||
|
"wchar_t", |
||||||
|
"while", |
||||||
|
"xor", |
||||||
|
"xor_eq", |
||||||
|
#ifdef PROTOBUF_FUTURE_CPP20_KEYWORDS // C++20 keywords.
|
||||||
|
"char8_t", |
||||||
|
"char16_t", |
||||||
|
"char32_t", |
||||||
|
"concept", |
||||||
|
"consteval", |
||||||
|
"constinit", |
||||||
|
"co_await", |
||||||
|
"co_return", |
||||||
|
"co_yield", |
||||||
|
"requires", |
||||||
|
#endif // !PROTOBUF_FUTURE_BREAKING_CHANGES
|
||||||
|
}; |
||||||
|
|
||||||
|
static std::unordered_set<std::string>* MakeKeywordsMap() { |
||||||
|
auto* result = new std::unordered_set<std::string>(); |
||||||
|
for (const auto keyword : kKeywordList) { |
||||||
|
result->emplace(keyword); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
static std::unordered_set<std::string>& kKeywords = *MakeKeywordsMap(); |
||||||
|
|
||||||
|
std::string ResolveKeywordConflict(const std::string& name) { |
||||||
|
if (kKeywords.count(name) > 0) { |
||||||
|
return name + "_"; |
||||||
|
} |
||||||
|
return name; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace upbc
|
@ -0,0 +1,40 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2021, Google LLC |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* * Neither the name of Google LLC nor the |
||||||
|
* names of its contributors may be used to endorse or promote products |
||||||
|
* derived from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef UPB_PROTOS_GENERATOR_KEYWORDS_H |
||||||
|
#define UPB_PROTOS_GENERATOR_KEYWORDS_H |
||||||
|
|
||||||
|
#include <string> |
||||||
|
|
||||||
|
namespace upbc { |
||||||
|
|
||||||
|
// Resolves proto field name conflict with C++ reserved keywords.
|
||||||
|
std::string ResolveKeywordConflict(const std::string& name); |
||||||
|
|
||||||
|
} // namespace upbc
|
||||||
|
|
||||||
|
#endif // UPB_PROTOS_GENERATOR_KEYWORDS_H
|
Loading…
Reference in new issue