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