@@ -851,6 +851,42 @@ static PyObject* GetIntegerEnumValue(const FieldDescriptor& descriptor,
851
851
return value;
852
852
}
853
853
854
+ void DeleteLastRepeatedWithSize (CMessage* self,
855
+ const FieldDescriptor* field_descriptor,
856
+ Py_ssize_t n) {
857
+ Message* message = self->message ;
858
+ const Reflection* reflection = message->GetReflection ();
859
+ ABSL_DCHECK (reflection->FieldSize (*message, field_descriptor) >= n);
860
+ Arena* arena = message->GetArena ();
861
+ ABSL_DCHECK_EQ (arena, nullptr )
862
+ << " python protobuf is expected to be allocated from heap" ;
863
+ for (; n > 0 ; n--) {
864
+ // It seems that RemoveLast() is less efficient for sub-messages, and
865
+ // the memory is not completely released. Prefer ReleaseLast().
866
+ //
867
+ // To work around a debug hardening (PROTOBUF_FORCE_COPY_IN_RELEASE),
868
+ // explicitly use UnsafeArenaReleaseLast. To not break rare use cases where
869
+ // arena is used, we fallback to ReleaseLast (but ABSL_DCHECK to find/fix
870
+ // it).
871
+ //
872
+ // Note that arena is likely null and ABSL_DCHECK and ReleaseLast might be
873
+ // redundant. The current approach takes extra cautious path not to disrupt
874
+ // production.
875
+ Message* sub_message =
876
+ (arena == nullptr )
877
+ ? reflection->UnsafeArenaReleaseLast (message, field_descriptor)
878
+ : reflection->ReleaseLast (message, field_descriptor);
879
+ // If there is a live weak reference to an item being removed, we "Release"
880
+ // it, and it takes ownership of the message.
881
+ if (CMessage* released = self->MaybeReleaseSubMessage (sub_message)) {
882
+ released->message = sub_message;
883
+ } else {
884
+ // sub_message was not transferred, delete it.
885
+ delete sub_message;
886
+ }
887
+ }
888
+ }
889
+
854
890
// Delete a slice from a repeated field.
855
891
// The only way to remove items in C++ protos is to delete the last one,
856
892
// so we swap items to move the deleted ones at the end, and then strip the
@@ -911,37 +947,14 @@ int DeleteRepeatedField(CMessage* self, const FieldDescriptor* field_descriptor,
911
947
}
912
948
}
913
949
914
- Arena* arena = message->GetArena ();
915
- ABSL_DCHECK_EQ (arena, nullptr )
916
- << " python protobuf is expected to be allocated from heap" ;
917
950
// Remove items, starting from the end.
918
- for (; length > to; length--) {
919
- if (field_descriptor->cpp_type () != FieldDescriptor::CPPTYPE_MESSAGE) {
951
+ if (field_descriptor->cpp_type () == FieldDescriptor::CPPTYPE_MESSAGE) {
952
+ DeleteLastRepeatedWithSize (self, field_descriptor, length - to);
953
+ } else {
954
+ ABSL_DCHECK_EQ (message->GetArena (), nullptr )
955
+ << " python protobuf is expected to be allocated from heap" ;
956
+ for (; length > to; length--) {
920
957
reflection->RemoveLast (message, field_descriptor);
921
- continue ;
922
- }
923
- // It seems that RemoveLast() is less efficient for sub-messages, and
924
- // the memory is not completely released. Prefer ReleaseLast().
925
- //
926
- // To work around a debug hardening (PROTOBUF_FORCE_COPY_IN_RELEASE),
927
- // explicitly use UnsafeArenaReleaseLast. To not break rare use cases where
928
- // arena is used, we fallback to ReleaseLast (but ABSL_DCHECK to find/fix
929
- // it).
930
- //
931
- // Note that arena is likely null and ABSL_DCHECK and ReleaseLast might be
932
- // redundant. The current approach takes extra cautious path not to disrupt
933
- // production.
934
- Message* sub_message =
935
- (arena == nullptr )
936
- ? reflection->UnsafeArenaReleaseLast (message, field_descriptor)
937
- : reflection->ReleaseLast (message, field_descriptor);
938
- // If there is a live weak reference to an item being removed, we "Release"
939
- // it, and it takes ownership of the message.
940
- if (CMessage* released = self->MaybeReleaseSubMessage (sub_message)) {
941
- released->message = sub_message;
942
- } else {
943
- // sub_message was not transferred, delete it.
944
- delete sub_message;
945
958
}
946
959
}
947
960
0 commit comments