Protocol Buffers - Google's data interchange format (grpc依赖) https://developers.google.com/protocol-buffers/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
8.5 KiB

// 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/decode.h"
#include "upb/mini_table/encode_internal.hpp"
#include "upb/mini_table/extension_internal.h"
#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_MiniTableExtension 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_MiniTableEnum* GetEnumTable(const protobuf::EnumDescriptor* d) const;
const upb_MiniTableExtension* GetExtension(
const protobuf::FieldDescriptor* fd) const;
// Get the initializer for the given sub-message/sub-enum link.
static std::string GetSub(upb_MiniTableSub 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* MakeMapMiniTable(const protobuf::Descriptor* m);
upb_MiniTable* MakeMessageSetMiniTable(const protobuf::Descriptor* m);
upb_MiniTable* MakeRegularMiniTable(const protobuf::Descriptor* m);
upb_MiniTableEnum* 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_MiniTableSub PackSub(const char* data, SubTag tag);
static bool IsNull(upb_MiniTableSub sub);
void SetSubTableStrings();
upb_MiniTableSub PackSubForField(const protobuf::FieldDescriptor* f,
const upb_MiniTableField* 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_MiniTableEnum*>;
using ExtensionMap = absl::flat_hash_map<const protobuf::FieldDescriptor*,
upb_MiniTableExtension>;
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_MiniTableEnum* GetEnumTable(
const protobuf::EnumDescriptor* d) const {
return layout64_.GetEnumTable(d);
}
std::string GetFieldOffset(const protobuf::FieldDescriptor* f) const {
const upb_MiniTableField* f_32 = upb_MiniTable_FindFieldByNumber(
GetMiniTable32(f->containing_type()), f->number());
const upb_MiniTableField* f_64 = upb_MiniTable_FindFieldByNumber(
GetMiniTable64(f->containing_type()), f->number());
return UpbSize(f_32->offset, f_64->offset);
}
std::string GetOneofCaseOffset(const protobuf::OneofDescriptor* o) const {
const protobuf::FieldDescriptor* f = o->field(0);
const upb_MiniTableField* f_32 = upb_MiniTable_FindFieldByNumber(
GetMiniTable32(f->containing_type()), f->number());
const upb_MiniTableField* f_64 = upb_MiniTable_FindFieldByNumber(
GetMiniTable64(f->containing_type()), f->number());
return UpbSize(~f_32->presence, ~f_64->presence);
}
std::string GetMessageSize(const protobuf::Descriptor* d) const {
return UpbSize(GetMiniTable32(d)->size, GetMiniTable64(d)->size);
}
int GetHasbitIndex(const protobuf::FieldDescriptor* f) const {
const upb_MiniTableField* 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_MiniTableExtension* GetExtension(
const protobuf::FieldDescriptor* f) const {
return layout64_.GetExtension(f);
}
template <class T>
static std::string UpbSize(T a, T b) {
if (a == b) return absl::Substitute("$0", a);
return absl::Substitute("UPB_SIZE($0, $1)", a, b);
}
private:
const protobuf::FileDescriptor* descriptor_;
FilePlatformLayout layout32_;
FilePlatformLayout layout64_;
};
} // namespace upbc
#endif // UPBC_FILE_LAYOUT_H