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