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