Move generator shared support code to common target.
PiperOrigin-RevId: 458257330
diff --git a/upbc/file_layout.h b/upbc/file_layout.h
new file mode 100644
index 0000000..271db45
--- /dev/null
+++ b/upbc/file_layout.h
@@ -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