Refactor `FieldArenaRep` to have a default implementation and add a `Get` method to recover the wrapped type, and unify object construction code under `CreateArenaCompatible`.

In the future, some field types will be wrapped in a containing type when they are individually allocated. To simplify code which needs to access the wrapped type, we will define a `Get` method on the `FieldArenaRep` helper struct, which will be defined by each field type overload to recover the wrapped type.

PiperOrigin-RevId: 811954764
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
index 5cee1ac..623d076 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -81,10 +81,7 @@
 template <typename Type>
 class GenericTypeHandler;  // defined in repeated_field.h
 
-template <typename T>
-struct IsRepeatedPtrFieldType;  // defined in repeated_ptr_field.h
-
-// This class maps field types to the types that we will use to represent them
+// This struct maps field types to the types that we will use to represent them
 // when allocated on an arena. This is necessary because fields no longer own an
 // arena pointer, but can be allocated directly on an arena. In this case, we
 // will use a wrapper class that holds both the arena pointer and the field, and
@@ -92,8 +89,31 @@
 //
 // Additionally, split pointer fields will use this representation when
 // allocated, regardless of whether they are on an arena or not.
+//
+// For example:
+// ```
+// template <>
+// struct FieldArenaRep<Message> {
+//   using Type = ArenaMessage;
+//   static Message* Get(ArenaMessage* arena_rep) {
+//     return &arena_rep->message();
+//   }
+// };
+// ```
 template <typename T>
-struct FieldArenaRep {};
+struct FieldArenaRep {
+  // The type of the field when allocated on an arena. By default, this is just
+  // `T`, but can be specialized to use a wrapper class that holds both the
+  // arena pointer and the field.
+  using Type = T;
+
+  // Returns a pointer to the field from the arena representation. By default,
+  // this is just a no-op, but can be specialized to extract the field from the
+  // wrapper class.
+  static T* PROTOBUF_NONNULL Get(Type* PROTOBUF_NONNULL arena_rep) {
+    return arena_rep;
+  }
+};
 
 template <typename T>
 void arena_delete_object(void* PROTOBUF_NONNULL object) {
@@ -240,12 +260,7 @@
           return static_cast<Type*>(CopyConstruct<Type>(arena, &args...));
         }
       }
-      if constexpr (internal::IsRepeatedPtrFieldType<Type>::value) {
-        return CreateRepeatedPtrFieldWithArena<Type>(
-            arena, std::forward<Args>(args)...);
-      } else {
-        return CreateArenaCompatible<Type>(arena, std::forward<Args>(args)...);
-      }
+      return CreateArenaCompatible<Type>(arena, std::forward<Args>(args)...);
     } else {
       if (ABSL_PREDICT_FALSE(arena == nullptr)) {
         return new T(std::forward<Args>(args)...);
@@ -485,7 +500,7 @@
     static PROTOBUF_ALWAYS_INLINE T* PROTOBUF_NONNULL New() {
       // Repeated pointer fields no longer have an arena constructor, so
       // specialize calling their default constructor.
-      if constexpr (internal::IsRepeatedPtrFieldType<T>::value) {
+      if constexpr (std::is_base_of_v<internal::RepeatedPtrFieldBase, T>) {
         return new T();
       } else {
         return new T(nullptr);
@@ -567,22 +582,6 @@
     if (ABSL_PREDICT_FALSE(arena == nullptr)) {
       return new T(nullptr, static_cast<Args&&>(args)...);
     } else {
-      return arena->DoCreateMessage<T>(static_cast<Args&&>(args)...);
-    }
-  }
-
-  template <typename T, typename... Args>
-  PROTOBUF_NDEBUG_INLINE static T* PROTOBUF_NONNULL
-  CreateRepeatedPtrFieldWithArena(Arena* PROTOBUF_NULLABLE arena,
-                                  Args&&... args) {
-    static_assert(is_arena_constructable<T>::value,
-                  "Can only construct types that are ArenaConstructable");
-    static_assert(internal::IsRepeatedPtrFieldType<T>::value,
-                  "Can only construct repeated pointer fields with "
-                  "CreateRepeatedPtrFieldWithArena");
-    if (ABSL_PREDICT_FALSE(arena == nullptr)) {
-      return new T(static_cast<Args&&>(args)...);
-    } else {
       using ArenaRepT = typename internal::FieldArenaRep<T>::Type;
       auto* arena_repr =
           arena->DoCreateMessage<ArenaRepT>(static_cast<Args&&>(args)...);
diff --git a/src/google/protobuf/repeated_ptr_field.h b/src/google/protobuf/repeated_ptr_field.h
index 335e4a2..b9a640d 100644
--- a/src/google/protobuf/repeated_ptr_field.h
+++ b/src/google/protobuf/repeated_ptr_field.h
@@ -972,37 +972,6 @@
 };
 
 
-template <typename T>
-struct IsRepeatedPtrFieldType {
-  static constexpr bool value = false;
-};
-
-template <>
-struct IsRepeatedPtrFieldType<RepeatedPtrFieldBase> {
-  static constexpr bool value = true;
-};
-
-template <typename Element>
-struct IsRepeatedPtrFieldType<RepeatedPtrField<Element>> {
-  static constexpr bool value = true;
-};
-
-template <>
-struct FieldArenaRep<RepeatedPtrFieldBase> {
-  // TODO - With removed arena pointers, we will need a class that
-  // holds both the arena pointer and the repeated field, and points the
-  // repeated to the arena pointer.
-  using Type = RepeatedPtrFieldBase;
-};
-
-template <typename Element>
-struct FieldArenaRep<RepeatedPtrField<Element>> {
-  // TODO - With removed arena pointers, we will need a class that
-  // holds both the arena pointer and the repeated field, and points the
-  // repeated to the arena pointer.
-  using Type = RepeatedPtrField<Element>;
-};
-
 }  // namespace internal
 
 // RepeatedPtrField is like RepeatedField, but used for repeated strings or